import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { api } from '../api/client'; import type { Remote } from '../api/types'; import { Badge } from '../components/Badge'; import { DataTable } from '../components/DataTable'; import './Remotes.css'; const typeColors: Record = { docker: 'blue', helm: 'green', rpm: 'yellow', pypi: 'blue', npm: 'red', generic: 'default', alpine: 'green', puppet: 'yellow', terraform: 'blue', goproxy: 'green', }; export function Remotes() { const navigate = useNavigate(); const [remotes, setRemotes] = useState([]); const [filter, setFilter] = useState(''); const [typeFilter, setTypeFilter] = useState(''); const [loading, setLoading] = useState(true); useEffect(() => { api.listRemotes() .then(r => setRemotes(r || [])) .finally(() => setLoading(false)); }, []); const remoteOnly = remotes.filter(r => r.repo_type !== 'local'); const types = [...new Set(remoteOnly.map(r => r.package_type))].sort(); const filtered = remoteOnly.filter(r => { if (typeFilter && r.package_type !== typeFilter) return false; if (filter && !r.name.toLowerCase().includes(filter.toLowerCase())) return false; return true; }); return (

Remotes

setFilter(e.target.value)} /> {filtered.length} remotes
{loading ? (
Loading...
) : ( {r.name}, }, { key: 'type', header: 'Type', render: (r: Remote) => ( {r.package_type} ), width: '110px', }, { key: 'description', header: 'Description', render: (r: Remote) => r.description || , }, { key: 'ttl', header: 'Mutable TTL', render: (r: Remote) => {r.mutable_ttl}s, width: '110px', }, { key: 'managed', header: 'Managed', render: (r: Remote) => r.managed_by ? {r.managed_by} : , width: '100px', }, ]} data={filtered} emptyMessage="No remotes match" onRowClick={(r) => navigate(`/remotes/${r.name}`)} /> )}
); }