import { useState, useEffect } from "react"; import type { ContractRepository, RepositorySourceType, RepositoryStatus, DaemonDirectory, RepositoryHistoryEntry, } from "../../lib/api"; import { getDaemonDirectories, getRepositorySuggestions } from "../../lib/api"; import { DirectoryInput } from "../mesh/DirectoryInput"; interface RepositoryPanelProps { repositories: ContractRepository[]; onAddRemote: (name: string, url: string, isPrimary: boolean) => void; onAddLocal: (name: string, path: string, isPrimary: boolean) => void; onCreateManaged: (name: string, isPrimary: boolean) => void; onDelete: (repoId: string) => void; onSetPrimary: (repoId: string) => void; } type AddMode = "remote" | "local" | "managed" | null; const sourceTypeLabels: Record = { remote: "Remote", local: "Local", managed: "Managed", }; const sourceTypeIcons: Record = { remote: "GH", local: "FS", managed: "MK", }; const statusColors: Record = { ready: "text-green-400", pending: "text-yellow-400", creating: "text-cyan-400", failed: "text-red-400", }; export function RepositoryPanel({ repositories, onAddRemote, onAddLocal, onCreateManaged, onDelete, onSetPrimary, }: RepositoryPanelProps) { const [addMode, setAddMode] = useState(null); const [name, setName] = useState(""); const [url, setUrl] = useState(""); const [path, setPath] = useState(""); const [isPrimary, setIsPrimary] = useState(false); // Daemon directory suggestions for local repositories const [suggestedDirectories, setSuggestedDirectories] = useState([]); // Repository history suggestions const [repoSuggestions, setRepoSuggestions] = useState([]); const [showSuggestions, setShowSuggestions] = useState(false); // Fetch daemon directories when "local" mode is selected useEffect(() => { if (addMode === "local") { getDaemonDirectories() .then((res) => setSuggestedDirectories(res.directories)) .catch(() => setSuggestedDirectories([])); } }, [addMode]); // Fetch repository suggestions when mode changes to remote or local useEffect(() => { if (addMode === "remote" || addMode === "local") { getRepositorySuggestions(addMode, undefined, 10) .then((res) => { setRepoSuggestions(res.entries); setShowSuggestions(res.entries.length > 0); }) .catch(() => { setRepoSuggestions([]); setShowSuggestions(false); }); } else { setRepoSuggestions([]); setShowSuggestions(false); } }, [addMode]); // Apply a suggestion to the form const applySuggestion = (suggestion: RepositoryHistoryEntry) => { setName(suggestion.name); if (suggestion.repositoryUrl) { setUrl(suggestion.repositoryUrl); } if (suggestion.localPath) { setPath(suggestion.localPath); } setShowSuggestions(false); }; const handleAdd = () => { if (!name.trim()) return; if (addMode === "remote" && url.trim()) { onAddRemote(name.trim(), url.trim(), isPrimary); } else if (addMode === "local" && path.trim()) { onAddLocal(name.trim(), path.trim(), isPrimary); } else if (addMode === "managed") { onCreateManaged(name.trim(), isPrimary); } // Reset form setAddMode(null); setName(""); setUrl(""); setPath(""); setIsPrimary(false); }; const handleCancel = () => { setAddMode(null); setName(""); setUrl(""); setPath(""); setIsPrimary(false); }; return (
{/* Repository list */} {repositories.length === 0 ? (

No repositories configured

) : (
{repositories.map((repo) => (
{/* Type icon */} {sourceTypeIcons[repo.sourceType]} {/* Name and details */}
{repo.name} {repo.isPrimary && ( Primary )}
{repo.repositoryUrl || repo.localPath || "(pending creation)"}
{/* Status */} {repo.status} {/* Actions */}
{!repo.isPrimary && repo.status === "ready" && ( )}
))}
)} {/* Add repository form */} {addMode ? (
Add {sourceTypeLabels[addMode]} Repository {repoSuggestions.length > 0 && ( )}
{/* Suggestions dropdown */} {showSuggestions && repoSuggestions.length > 0 && (
{repoSuggestions.map((suggestion) => ( ))}
)} setName(e.target.value)} placeholder="Repository name" className="w-full px-3 py-2 bg-[#0d1b2d] border border-[#3f6fb3] text-[#dbe7ff] font-mono text-xs focus:outline-none focus:border-[#75aafc]" /> {addMode === "remote" && ( setUrl(e.target.value)} placeholder="https://github.com/owner/repo" className="w-full px-3 py-2 bg-[#0d1b2d] border border-[#3f6fb3] text-[#dbe7ff] font-mono text-xs focus:outline-none focus:border-[#75aafc]" /> )} {addMode === "local" && ( )} {addMode === "managed" && (

Makima will create this repository via the daemon.

)}
) : (
)}
); }