import { useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import { api } from '../api/client'; import type { Remote, Virtual } from '../api/types'; import { Badge } from '../components/Badge'; import { DataTable } from '../components/DataTable'; import './Virtuals.css'; export function Virtuals() { const [virtuals, setVirtuals] = useState([]); const [remoteMap, setRemoteMap] = useState>({}); const [loading, setLoading] = useState(true); const [expanded, setExpanded] = useState(null); useEffect(() => { Promise.all([api.listVirtuals(), api.listRemotes()]) .then(([v, r]) => { setVirtuals(v || []); const map: Record = {}; for (const remote of r || []) { map[remote.name] = remote; } setRemoteMap(map); }) .finally(() => setLoading(false)); }, []); function memberLink(name: string) { const remote = remoteMap[name]; if (remote?.repo_type === 'local') { return `/locals/${name}`; } return `/remotes/${name}`; } return (

Virtual Repositories

{loading ? (
Loading...
) : ( {v.name}, }, { key: 'type', header: 'Type', render: (v: Virtual) => {v.package_type}, width: '110px', }, { key: 'members', header: 'Members', render: (v: Virtual) => ( {v.members?.length || 0} repos ), width: '110px', }, { key: 'description', header: 'Description', render: (v: Virtual) => v.description || , }, { key: 'managed', header: 'Managed', render: (v: Virtual) => v.managed_by ? {v.managed_by} : , width: '100px', }, ]} data={virtuals} emptyMessage="No virtual repositories configured" onRowClick={(v) => setExpanded(expanded === v.name ? null : v.name)} /> )} {expanded && (

Members of {expanded}

    {virtuals .find(v => v.name === expanded) ?.members?.map((m, i) => { const remote = remoteMap[m]; const typeLabel = remote?.repo_type === 'local' ? 'local' : 'remote'; return (
  • {i + 1} {m} {typeLabel}
  • ); })}
)}
); }