From 87044a747b47bd83249d61a45842c7f7b2eae56d Mon Sep 17 00:00:00 2001 From: soryu Date: Sun, 11 Jan 2026 05:52:14 +0000 Subject: Contract system --- .../src/components/contracts/RepositoryPanel.tsx | 260 +++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 makima/frontend/src/components/contracts/RepositoryPanel.tsx (limited to 'makima/frontend/src/components/contracts/RepositoryPanel.tsx') diff --git a/makima/frontend/src/components/contracts/RepositoryPanel.tsx b/makima/frontend/src/components/contracts/RepositoryPanel.tsx new file mode 100644 index 0000000..4170cfb --- /dev/null +++ b/makima/frontend/src/components/contracts/RepositoryPanel.tsx @@ -0,0 +1,260 @@ +import { useState, useEffect } from "react"; +import type { + ContractRepository, + RepositorySourceType, + RepositoryStatus, + DaemonDirectory, +} from "../../lib/api"; +import { getDaemonDirectories } 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([]); + + // Fetch daemon directories when "local" mode is selected + useEffect(() => { + if (addMode === "local") { + getDaemonDirectories() + .then((res) => setSuggestedDirectories(res.directories)) + .catch(() => setSuggestedDirectories([])); + } + }, [addMode]); + + 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 + +
+ + 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. +

+ )} + + + +
+ + +
+
+ ) : ( +
+ + + +
+ )} +
+ ); +} -- cgit v1.2.3