This commit is contained in:
mats committed 2026-09-12 20:29:38 +02:00
1 parent 61df5e3dcc
commit c0a94d3b6d
25 files changed
+2143 -348

No files matched your search

+149
View File
@@ -0,0 +1,149 @@
import { useState, useMemo } from 'react'
import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from '../ui/Table'
import { Badge } from '../ui/Badge'
import { Kbd } from '../ui/Kbd'
import { EmptyState, EmptyStateIcon, EmptyStateTitle, EmptyStateDescription } from '../ui/EmptyState'
import { Icon } from '../Icon'
type Service = {
id: string
name: string
region: string
status: 'healthy' | 'degraded' | 'scaling'
latency: string
memory: string
instances: number
}
const INITIAL_SERVICES: Service[] = [
{ id: '1', name: 'api-gateway', region: 'us-east-1', status: 'healthy', latency: '12ms', memory: '128 MB', instances: 8 },
{ id: '2', name: 'vector-indexer', region: 'eu-central-1', status: 'healthy', latency: '34ms', memory: '890 MB', instances: 4 },
{ id: '3', name: 'model-inference', region: 'us-west-2', status: 'scaling', latency: '78ms', memory: '4.2 GB', instances: 16 },
{ id: '4', name: 'session-broker', region: 'us-east-1', status: 'healthy', latency: '8ms', memory: '64 MB', instances: 6 },
{ id: '5', name: 'analytics-worker', region: 'ap-northeast-1', status: 'degraded', latency: '142ms', memory: '1.8 GB', instances: 2 },
{ id: '6', name: 'audit-logger', region: 'eu-west-1', status: 'healthy', latency: '19ms', memory: '210 MB', instances: 3 },
]
export function ServiceTable() {
const [search, setSearch] = useState('')
const [filterStatus, setFilterStatus] = useState<string>('all')
const filteredServices = useMemo(() => {
return INITIAL_SERVICES.filter(svc => {
const matchesSearch = svc.name.toLowerCase().includes(search.toLowerCase()) ||
svc.region.toLowerCase().includes(search.toLowerCase())
const matchesStatus = filterStatus === 'all' || svc.status === filterStatus
return matchesSearch && matchesStatus
})
}, [search, filterStatus])
return (
<div className="stack-md">
{/* Table Toolbar */}
<div className="flex-between" style={{ flexWrap: 'wrap', gap: 'var(--space-3)' }}>
<div className="icon-search-bar" style={{ maxWidth: 320 }}>
<Icon name="search" size={15} />
<input
type="text"
placeholder="Filter services or regions..."
value={search}
onChange={e => setSearch(e.target.value)}
className="icon-search-input"
/>
{search && (
<button className="icon-clear-btn" onClick={() => setSearch('')}>
<Icon name="close" size={13} />
</button>
)}
</div>
<div className="row-xs">
{['all', 'healthy', 'scaling', 'degraded'].map(st => (
<button
key={st}
className={`button ${filterStatus === st ? 'secondary' : 'ghost'}`}
style={{
padding: 'var(--space-1) var(--space-3)',
fontSize: 'var(--text-xs)',
textTransform: 'capitalize',
}}
onClick={() => setFilterStatus(st)}
>
{st}
</button>
))}
</div>
</div>
{/* Table Surface */}
{filteredServices.length > 0 ? (
<Table>
<TableHeader>
<TableRow>
<TableHead>Service Name</TableHead>
<TableHead>Region</TableHead>
<TableHead>Status</TableHead>
<TableHead>P99 Latency</TableHead>
<TableHead>Memory</TableHead>
<TableHead>Nodes</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{filteredServices.map(svc => (
<TableRow key={svc.id}>
<TableCell style={{ fontWeight: 600 }}>
<div className="row-xs" style={{ alignItems: 'center' }}>
<span
style={{
width: 7,
height: 7,
borderRadius: '50%',
background: svc.status === 'healthy' ? 'var(--chart-2)' : svc.status === 'scaling' ? 'var(--primary)' : 'var(--destructive)',
boxShadow: `0 0 8px ${svc.status === 'healthy' ? 'var(--chart-2)' : svc.status === 'scaling' ? 'var(--primary)' : 'var(--destructive)'}`,
}}
/>
{svc.name}
</div>
</TableCell>
<TableCell>
<Kbd>{svc.region}</Kbd>
</TableCell>
<TableCell>
<Badge
variant={svc.status === 'healthy' ? 'positive' : svc.status === 'scaling' ? 'primary' : 'destructive'}
>
{svc.status}
</Badge>
</TableCell>
<TableCell className="mono" style={{ color: svc.status === 'degraded' ? 'var(--destructive)' : 'var(--primary)' }}>
{svc.latency}
</TableCell>
<TableCell className="mono" style={{ color: 'var(--muted-foreground)' }}>
{svc.memory}
</TableCell>
<TableCell className="mono" style={{ color: 'var(--foreground)' }}>
{svc.instances}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
) : (
<EmptyState>
<EmptyStateIcon>
<Icon name="search" size={24} />
</EmptyStateIcon>
<EmptyStateTitle>No matching services</EmptyStateTitle>
<EmptyStateDescription>
No active nodes or services match the current filter query "{search}".
</EmptyStateDescription>
</EmptyState>
)}
<div className="flex-between muted" style={{ fontSize: 'var(--text-3xs)', padding: '0 var(--space-2)' }}>
<span>Showing {filteredServices.length} of {INITIAL_SERVICES.length} deployed services</span>
<span className="mono">Synced live via cluster coordinator</span>
</div>
</div>
)
}