Move to threads based system.

This commit is contained in:
Gabriel Brown
2026-06-22 10:37:26 -04:00
parent 8ae6c4b533
commit 206b64176b
82 changed files with 6169 additions and 1930 deletions
+26 -21
View File
@@ -3,9 +3,9 @@
import Link from 'next/link';
import { MetricCard } from '@/components/dashboard/metric-card';
import { SpoonCard } from '@/components/spoons/spoon-card';
import { MaintenanceQueue } from '@/components/updates/maintenance-queue';
import { MaintenanceQueue } from '@/components/threads/maintenance-queue';
import { useQuery } from 'convex/react';
import { Bot, GitBranch, RefreshCw, ShieldCheck } from 'lucide-react';
import { GitBranch, MessageSquare, RefreshCw, ShieldCheck } from 'lucide-react';
import { api } from '@spoon/backend/convex/_generated/api.js';
import { Button, Card, CardContent, CardHeader, CardTitle } from '@spoon/ui';
@@ -13,9 +13,7 @@ import { Button, Card, CardContent, CardHeader, CardTitle } from '@spoon/ui';
const DashboardPage = () => {
const spoons = useQuery(api.spoons.listMine, {}) ?? [];
const syncRuns = useQuery(api.syncRuns.listRecent, { limit: 5 }) ?? [];
const agentRequests =
useQuery(api.agentRequests.listRecent, { limit: 5 }) ?? [];
const aiReviews = useQuery(api.aiReviews.listRecent, { limit: 5 }) ?? [];
const threads = useQuery(api.threads.listMine, { limit: 25 }) ?? [];
const activeSpoons = spoons.filter(
(spoon) => spoon.status === 'active',
).length;
@@ -34,7 +32,8 @@ const DashboardPage = () => {
<div>
<h1 className='text-3xl font-semibold tracking-normal'>Dashboard</h1>
<p className='text-muted-foreground mt-2'>
Monitor managed forks, upstream activity, and queued agent work.
Monitor managed forks, upstream activity, and open maintenance
threads.
</p>
</div>
<Button asChild>
@@ -56,10 +55,17 @@ const DashboardPage = () => {
icon={RefreshCw}
/>
<MetricCard
label='Agent requests'
value={agentRequests.length}
note='Queued and recent'
icon={Bot}
label='Open threads'
value={
threads.filter(
(thread) =>
!['resolved', 'ignored', 'failed', 'cancelled'].includes(
thread.status,
),
).length
}
note='Across all Spoons'
icon={MessageSquare}
/>
<MetricCard
label='Upstream commits'
@@ -71,7 +77,7 @@ const DashboardPage = () => {
<section className='space-y-3'>
<h2 className='text-lg font-semibold'>Maintenance queue</h2>
<MaintenanceQueue spoons={spoons} />
<MaintenanceQueue threads={threads} />
</section>
<div className='grid gap-6 xl:grid-cols-2'>
@@ -126,29 +132,28 @@ const DashboardPage = () => {
</Card>
<Card className='mt-4 shadow-none'>
<CardHeader>
<CardTitle className='text-base'>AI reviews</CardTitle>
<CardTitle className='text-base'>Recent threads</CardTitle>
</CardHeader>
<CardContent>
{aiReviews.length ? (
{threads.length ? (
<div className='space-y-3'>
{aiReviews.map((review) => (
{threads.slice(0, 5).map((thread) => (
<div
key={review._id}
key={thread._id}
className='border-border border p-3 text-sm'
>
<p className='font-medium capitalize'>
{review.risk} risk
</p>
<p className='font-medium'>{thread.title}</p>
<p className='text-muted-foreground'>
{review.outputSummary ?? review.inputSummary}
{thread.status.replaceAll('_', ' ')} ·{' '}
{thread.source.replaceAll('_', ' ')}
</p>
</div>
))}
</div>
) : (
<p className='text-muted-foreground text-sm'>
OpenAI compatibility reviews will appear here after you run
them on a Spoon.
Threads appear when you request work or upstream changes need
review.
</p>
)}
</CardContent>