Skip to content

Commit 3064929

Browse files
jmbish04claude
andcommitted
feat: add beta tracker views (list, board, reports) with sentinel API integration
Adds Linear/ClickUp-inspired project tracker under projects/tracker-beta with three nested views (list, board, reports), a master layout shell with AI assistant sidebar, and sidebar nav links. All views fetch from the sentinel backend APIs with graceful fallback to mock data. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5795602 commit 3064929

3 files changed

Lines changed: 90 additions & 29 deletions

File tree

src/frontend/src/components/layout/RepoFolder.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ import {
2020
Wrench,
2121
ChevronDown,
2222
Component,
23-
Layers
23+
Layers,
24+
LayoutList,
25+
KanbanSquare
2426
} from 'lucide-react';
2527
import { useQuery } from '@tanstack/react-query';
2628
import { Badge } from '@/components/ui/badge';
@@ -66,6 +68,9 @@ export function RepoFolder({ repo }: RepoFolderProps) {
6668
{ slug: "plan", label: "AI Planner", icon: Sparkles },
6769
{ slug: "projects", label: "Backlog", icon: ListChecks },
6870
{ slug: "projects/tracker", label: "Projects [Beta]", icon: Layers },
71+
{ slug: "projects/tracker-beta/list", label: "Tracker List [Beta]", icon: LayoutList },
72+
{ slug: "projects/tracker-beta/board", label: "Tracker Board [Beta]", icon: KanbanSquare },
73+
{ slug: "projects/tracker-beta/reports", label: "Tracker Reports [Beta]", icon: BarChart3 },
6974
{ slug: "prs", label: "PRs", icon: GitPullRequest, badge: activePrCount > 0 ? activePrCount : null },
7075
];
7176

src/frontend/src/routes/RepoRoutes.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ import RepoProjects from "@/views/repos/Projects";
3939
import RepoProjectsBeta from "@/views/repos/ProjectsBeta";
4040
import RepoKanban from "@/views/repos/KanbanBoard";
4141

42+
// Beta Tracker views (Linear/ClickUp-inspired)
43+
import TrackerLayoutBeta from "@/views/repos/TrackerLayoutBeta";
44+
import TrackerListViewBeta from "@/views/repos/TrackerListViewBeta";
45+
import TrackerBoardViewBeta from "@/views/repos/TrackerBoardViewBeta";
46+
import TrackerReportsViewBeta from "@/views/repos/TrackerReportsViewBeta";
47+
4248
// Global views reused in repo context (scoped by RepoLayout context provider)
4349
// Retained for routes that haven't yet been given dedicated repo-scoped variants.
4450
import ProjectView from "@/views/repos/Overview";
@@ -93,6 +99,14 @@ export function RepoRoutes() {
9399
{/* /repos/:owner/:repo/projects — repo project board (dedicated) */}
94100
<Route path="projects" element={<RepoProjects />} />
95101
<Route path="projects/tracker" element={<RepoProjectsBeta />} />
102+
103+
{/* Beta Tracker — layout route with nested list/board/reports views */}
104+
<Route path="projects/tracker-beta" element={<TrackerLayoutBeta />}>
105+
<Route index element={<Navigate to="list" replace />} />
106+
<Route path="list" element={<TrackerListViewBeta />} />
107+
<Route path="board" element={<TrackerBoardViewBeta />} />
108+
<Route path="reports" element={<TrackerReportsViewBeta />} />
109+
</Route>
96110
<Route path="projects/:projectId" element={guard(<ProjectView />)} />
97111

98112
{/* Work items within a project */}

src/frontend/src/views/repos/TrackerReportsViewBeta.tsx

Lines changed: 70 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/**
22
* @file views/repos/TrackerReportsViewBeta.tsx
3-
* Analytics dashboard with AI insights, velocity chart,
3+
* Stats & reports dashboard with AI insights, velocity chart,
44
* and team workload visualization.
55
*
6-
* Fetches system status from /api/projects/sentinel/status.
6+
* Fetches from /api/projects/sentinel/status for live metrics.
77
*/
88

99
import React, { useState, useEffect } from "react";
@@ -12,17 +12,16 @@ import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/com
1212
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
1313
import { TrendingUp, AlertTriangle, Users, Activity, CheckCircle2, Bot, Loader2 } from "lucide-react";
1414

15-
interface SentinelStatus {
15+
interface StatusData {
1616
totalTasks: number;
17-
availableTasks: number;
18-
claimedTasks: number;
17+
activeTasks: number;
1918
completedTasks: number;
20-
recentEvents: any[];
19+
blockedTasks: number;
2120
}
2221

2322
export default function TrackerReportsViewBeta() {
2423
const { owner, repo } = useParams();
25-
const [status, setStatus] = useState<SentinelStatus | null>(null);
24+
const [status, setStatus] = useState<StatusData | null>(null);
2625
const [loading, setLoading] = useState(true);
2726

2827
useEffect(() => {
@@ -34,9 +33,16 @@ export default function TrackerReportsViewBeta() {
3433
});
3534
if (!res.ok) throw new Error("Failed to fetch");
3635
const data = await res.json();
37-
if (!cancelled) setStatus(data);
36+
if (!cancelled) {
37+
setStatus({
38+
totalTasks: data.totalTasks ?? data.taskCounts?.total ?? 0,
39+
activeTasks: data.activeTasks ?? data.taskCounts?.active ?? 0,
40+
completedTasks: data.completedTasks ?? data.taskCounts?.completed ?? 0,
41+
blockedTasks: data.blockedTasks ?? data.taskCounts?.blocked ?? 0,
42+
});
43+
}
3844
} catch {
39-
// Use fallback
45+
// Use defaults
4046
} finally {
4147
if (!cancelled) setLoading(false);
4248
}
@@ -45,14 +51,47 @@ export default function TrackerReportsViewBeta() {
4551
return () => { cancelled = true; };
4652
}, [owner, repo]);
4753

48-
const totalTasks = status?.totalTasks ?? 42;
49-
const completedTasks = status?.completedTasks ?? 28;
50-
const completionPct = totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0;
51-
5254
const workload = [
5355
{ name: "Alex M.", tasks: 12, capacity: 15, color: "bg-indigo-500" },
5456
{ name: "Sarah J.", tasks: 18, capacity: 15, color: "bg-rose-500" },
55-
{ name: "AI Agent", tasks: status?.claimedTasks ?? 45, capacity: 100, color: "bg-emerald-500" },
57+
{ name: "AI Agent", tasks: 45, capacity: 100, color: "bg-emerald-500" },
58+
];
59+
60+
const completionPct = status
61+
? status.totalTasks > 0
62+
? Math.round((status.completedTasks / status.totalTasks) * 100)
63+
: 0
64+
: 68;
65+
66+
const metrics = [
67+
{
68+
label: "Sprint Completion",
69+
value: `${completionPct}%`,
70+
icon: CheckCircle2,
71+
color: "text-emerald-400",
72+
sub: status ? `${status.completedTasks} of ${status.totalTasks} tasks` : "+12% from last sprint",
73+
},
74+
{
75+
label: "Active Tasks",
76+
value: status ? String(status.activeTasks) : "4",
77+
icon: Activity,
78+
color: "text-indigo-400",
79+
sub: status ? "Currently in progress" : "2 at risk of delay",
80+
},
81+
{
82+
label: "Cycle Time",
83+
value: "2.4d",
84+
icon: TrendingUp,
85+
color: "text-amber-400",
86+
sub: "-0.5d improvement",
87+
},
88+
{
89+
label: "Bottlenecks",
90+
value: status ? String(status.blockedTasks) : "3",
91+
icon: AlertTriangle,
92+
color: "text-rose-400",
93+
sub: "Waiting on external APIs",
94+
},
5695
];
5796

5897
if (loading) {
@@ -65,25 +104,19 @@ export default function TrackerReportsViewBeta() {
65104

66105
return (
67106
<div className="h-full overflow-y-auto pr-2 space-y-6">
68-
69107
{/* AI Callout Alert */}
70108
<Alert className="bg-indigo-500/10 border-indigo-500/20 text-indigo-200 shadow-xl shadow-indigo-500/5">
71109
<Bot className="h-4 w-4 text-indigo-400" />
72110
<AlertTitle className="font-semibold text-indigo-300">AI Project Insights</AlertTitle>
73111
<AlertDescription className="text-indigo-200/80 text-xs mt-1 leading-relaxed">
74-
Velocity has increased by 14% this sprint. However, <strong>Sarah J.</strong> is over capacity.
75-
Consider dispatching a Code Review agent to unblock her tasks currently in review.
112+
Velocity has increased by 14% this sprint. However, <strong>Sarah J.</strong> is over
113+
capacity. Consider dispatching a Code Review agent to unblock her tasks currently in review.
76114
</AlertDescription>
77115
</Alert>
78116

79117
{/* Top Metrics Strip */}
80118
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
81-
{[
82-
{ label: "Sprint Completion", value: `${completionPct}%`, icon: CheckCircle2, color: "text-emerald-400", sub: `${completedTasks}/${totalTasks} tasks done` },
83-
{ label: "Active Epics", value: "4", icon: Activity, color: "text-indigo-400", sub: "2 at risk of delay" },
84-
{ label: "Cycle Time", value: "2.4d", icon: TrendingUp, color: "text-amber-400", sub: "-0.5d improvement" },
85-
{ label: "Bottlenecks", value: String(status?.availableTasks ?? 3), icon: AlertTriangle, color: "text-rose-400", sub: "Unclaimed tasks" },
86-
].map((stat, i) => (
119+
{metrics.map((stat, i) => (
87120
<Card key={i} className="bg-zinc-900/50 border-zinc-800/50 shadow-sm">
88121
<CardContent className="p-5">
89122
<div className="flex justify-between items-start mb-2">
@@ -104,7 +137,9 @@ export default function TrackerReportsViewBeta() {
104137
<div className="flex items-center justify-between">
105138
<div>
106139
<CardTitle className="text-base text-zinc-100">Velocity &amp; Burndown</CardTitle>
107-
<CardDescription className="text-xs text-zinc-500">Tasks closed over the last 14 days</CardDescription>
140+
<CardDescription className="text-xs text-zinc-500">
141+
Tasks closed over the last 14 days
142+
</CardDescription>
108143
</div>
109144
<TrendingUp className="w-4 h-4 text-zinc-500" />
110145
</div>
@@ -113,7 +148,15 @@ export default function TrackerReportsViewBeta() {
113148
<div className="h-[200px] w-full flex items-end justify-between gap-2 px-2 pt-4 border-b border-zinc-800/50 relative">
114149
{/* Ideal line overlay */}
115150
<svg className="absolute inset-0 h-full w-full" preserveAspectRatio="none">
116-
<line x1="0" y1="20" x2="100%" y2="180" stroke="rgba(99,102,241,0.3)" strokeWidth="2" strokeDasharray="4 4" />
151+
<line
152+
x1="0"
153+
y1="20"
154+
x2="100%"
155+
y2="180"
156+
stroke="rgba(99,102,241,0.3)"
157+
strokeWidth="2"
158+
strokeDasharray="4 4"
159+
/>
117160
</svg>
118161
{/* CSS Bar Chart */}
119162
{[40, 60, 30, 80, 90, 45, 65, 100, 75, 50].map((h, i) => (
@@ -159,10 +202,9 @@ export default function TrackerReportsViewBeta() {
159202
{member.tasks} / {member.capacity} tasks
160203
</span>
161204
</div>
162-
{/* Custom progress bar to support dynamic colors */}
163-
<div className="h-1.5 w-full bg-zinc-800 rounded-full overflow-hidden">
205+
<div className="relative h-1.5 w-full overflow-hidden rounded-full bg-zinc-800">
164206
<div
165-
className={cn("h-full rounded-full transition-all", isOver ? "bg-rose-500" : member.color)}
207+
className={`h-full rounded-full transition-all ${isOver ? "bg-rose-500" : member.color}`}
166208
style={{ width: `${Math.min(pct, 100)}%` }}
167209
/>
168210
</div>

0 commit comments

Comments
 (0)