import { useEffect, useState, useCallback } from 'react'; import { useParams, Link } from 'react-router-dom'; import { api } from '../api/client'; import type { Artifact } from '../api/types'; import { DataTable } from '../components/DataTable'; import { formatBytes, timeAgo, truncateHash } from '../components/format'; import './Objects.css'; export function Objects() { const { name } = useParams<{ name: string }>(); const [artifacts, setArtifacts] = useState([]); const [page, setPage] = useState(1); const [loading, setLoading] = useState(true); const [filter, setFilter] = useState(''); const load = useCallback(() => { if (!name) return; setLoading(true); api.listObjects(name, page, 50) .then(a => setArtifacts(a || [])) .finally(() => setLoading(false)); }, [name, page]); useEffect(() => { load(); }, [load]); const handleEvict = async (path: string) => { if (!name || !confirm(`Evict ${path}?`)) return; await api.evictObject(name, path); load(); }; const filtered = filter ? artifacts.filter(a => a.path.toLowerCase().includes(filter.toLowerCase())) : artifacts; return (
← {name}

Cached Objects

setFilter(e.target.value)} /> {filtered.length} objects
{loading ? (
Loading...
) : ( <> {a.path}, }, { key: 'size', header: 'Size', render: (a: Artifact) => formatBytes(a.size_bytes), width: '100px', }, { key: 'hash', header: 'Hash', render: (a: Artifact) => ( {truncateHash(a.content_hash)} ), width: '160px', }, { key: 'accessed', header: 'Last Accessed', render: (a: Artifact) => timeAgo(a.last_accessed_at), width: '120px', }, { key: 'hits', header: 'Hits', render: (a: Artifact) => a.access_count, width: '70px', }, { key: 'actions', header: '', render: (a: Artifact) => ( ), width: '80px', }, ]} data={filtered} emptyMessage="No cached objects" />
Page {page}
)}
); }