Files
2026-05-18 14:47:16 -07:00

151 lines
4.9 KiB
TypeScript

'use client';
import { useState } from 'react';
import { Badge } from '@/components/ui/badge';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { BenchmarkBar, BenchmarkChart } from './BenchmarkChart';
import type { WorldsStatus } from './types';
import { WorldCard } from './WorldCard';
interface WorldsDashboardProps {
data: WorldsStatus;
}
export function WorldsDashboard({ data }: WorldsDashboardProps) {
const [filter, setFilter] = useState<'all' | 'official' | 'community'>('all');
const worlds = Object.entries(data.worlds);
const officialWorlds = worlds.filter(([, w]) => w.type === 'official');
const communityWorlds = worlds.filter(([, w]) => w.type === 'community');
const filteredWorlds =
filter === 'all'
? worlds
: filter === 'official'
? officialWorlds
: communityWorlds;
// Calculate summary stats
const stats = {
total: worlds.length,
official: officialWorlds.length,
community: communityWorlds.length,
};
// Get benchmark names for the bar chart
const benchmarkNames = new Set<string>();
for (const [, world] of worlds) {
if (world.benchmark?.metrics) {
for (const name of Object.keys(world.benchmark.metrics)) {
benchmarkNames.add(name);
}
}
}
const sortedBenchmarks = Array.from(benchmarkNames).sort();
return (
<div className="space-y-8">
{/* Summary */}
<div className="flex flex-wrap gap-3">
<Badge variant="outline" className="text-sm py-1 px-3">
{stats.total} Worlds
</Badge>
<Badge variant="outline" className="text-sm py-1 px-3">
{stats.official} Official
</Badge>
<Badge variant="outline" className="text-sm py-1 px-3">
🌐 {stats.community} Community
</Badge>
</div>
{/* Tabs */}
<Tabs defaultValue="overview" className="w-full">
<TabsList>
<TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="benchmarks">Benchmarks</TabsTrigger>
</TabsList>
<TabsContent value="overview" className="space-y-6 pt-4">
{/* Filter */}
<div className="flex gap-2">
<button
type="button"
onClick={() => setFilter('all')}
className={`px-3 py-1 text-sm rounded-md transition-colors ${
filter === 'all'
? 'bg-primary text-primary-foreground'
: 'bg-muted hover:bg-muted/80'
}`}
>
All ({stats.total})
</button>
<button
type="button"
onClick={() => setFilter('official')}
className={`px-3 py-1 text-sm rounded-md transition-colors ${
filter === 'official'
? 'bg-primary text-primary-foreground'
: 'bg-muted hover:bg-muted/80'
}`}
>
Official ({stats.official})
</button>
<button
type="button"
onClick={() => setFilter('community')}
className={`px-3 py-1 text-sm rounded-md transition-colors ${
filter === 'community'
? 'bg-primary text-primary-foreground'
: 'bg-muted hover:bg-muted/80'
}`}
>
Community ({stats.community})
</button>
</div>
{/* World Cards */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{filteredWorlds.map(([id, world]) => (
<WorldCard key={id} id={id} world={world} />
))}
</div>
</TabsContent>
<TabsContent value="benchmarks" className="space-y-8 pt-4">
{/* Benchmark comparison */}
<div className="space-y-4">
<h3 className="text-lg font-semibold">Performance Comparison</h3>
<p className="text-sm text-muted-foreground">
Average workflow execution time across all worlds. Lower is
better.
</p>
<BenchmarkChart data={data} />
</div>
{/* Individual benchmark bars */}
{sortedBenchmarks.slice(0, 3).map((benchName) => (
<div key={benchName} className="space-y-3">
<h4 className="text-md font-medium">{benchName}</h4>
<BenchmarkBar data={data} benchmarkName={benchName} />
</div>
))}
</TabsContent>
</Tabs>
{/* Last updated */}
<div className="text-xs text-muted-foreground border-t pt-4">
Last updated: {new Date(data.lastUpdated).toLocaleString()}
{data.commit && (
<>
{' · '}
Commit:{' '}
<code className="text-xs bg-muted px-1 rounded">
{data.commit.slice(0, 7)}
</code>
</>
)}
</div>
</div>
);
}