From 6b9b62404489fb55a2c52d7b75730be16efbec3e Mon Sep 17 00:00:00 2001 From: soryu Date: Sat, 7 Feb 2026 19:17:49 +0000 Subject: Add repo suggestions for directives --- makima/frontend/src/routes/directives.tsx | 198 +++++++++++++++++++++++++----- 1 file changed, 170 insertions(+), 28 deletions(-) diff --git a/makima/frontend/src/routes/directives.tsx b/makima/frontend/src/routes/directives.tsx index 939961c..fd3808b 100644 --- a/makima/frontend/src/routes/directives.tsx +++ b/makima/frontend/src/routes/directives.tsx @@ -3,11 +3,19 @@ import { useParams, useNavigate } from "react-router"; import { Masthead } from "../components/Masthead"; import { DirectiveList } from "../components/directives/DirectiveList"; import { DirectiveDetail } from "../components/directives/DirectiveDetail"; +import { DirectoryInput } from "../components/mesh/DirectoryInput"; import { useDirectives } from "../hooks/useDirectives"; import { useAuth } from "../contexts/AuthContext"; +import { + getDaemonDirectories, + getRepositorySuggestions, +} from "../lib/api"; import type { DirectiveWithChains, CreateDirectiveRequest, + RepositorySourceType, + DaemonDirectory, + RepositoryHistoryEntry, } from "../lib/api"; export default function DirectivesPage() { @@ -58,7 +66,52 @@ function DirectivesContent() { const [showCreateForm, setShowCreateForm] = useState(false); const [createTitle, setCreateTitle] = useState(""); const [createGoal, setCreateGoal] = useState(""); - const [createRepoUrl, setCreateRepoUrl] = useState(""); + + // Repository state + const [repoType, setRepoType] = useState("remote"); + const [repoUrl, setRepoUrl] = useState(""); + const [repoPath, setRepoPath] = useState(""); + const [suggestedDirectories, setSuggestedDirectories] = useState([]); + const [repoSuggestions, setRepoSuggestions] = useState([]); + const [showRepoSuggestions, setShowRepoSuggestions] = useState(false); + + // Fetch repository suggestions when modal opens and repo type changes + useEffect(() => { + if (showCreateForm && (repoType === "remote" || repoType === "local")) { + getRepositorySuggestions(repoType, undefined, 10) + .then((res) => { + setRepoSuggestions(res.entries); + setShowRepoSuggestions(res.entries.length > 0); + }) + .catch(() => { + setRepoSuggestions([]); + setShowRepoSuggestions(false); + }); + } else { + setRepoSuggestions([]); + setShowRepoSuggestions(false); + } + }, [showCreateForm, repoType]); + + // Fetch daemon directories when "local" repo type is selected + useEffect(() => { + if (repoType === "local" && showCreateForm) { + getDaemonDirectories() + .then((res) => setSuggestedDirectories(res.directories)) + .catch(() => setSuggestedDirectories([])); + } + }, [repoType, showCreateForm]); + + // Apply a repository suggestion + const applyRepoSuggestion = useCallback((suggestion: RepositoryHistoryEntry) => { + if (suggestion.repositoryUrl) { + setRepoUrl(suggestion.repositoryUrl); + } + if (suggestion.localPath) { + setRepoPath(suggestion.localPath); + } + setShowRepoSuggestions(false); + }, []); // Load directive when ID changes useEffect(() => { @@ -84,6 +137,15 @@ function DirectivesContent() { navigate("/directives"); }, [navigate]); + const resetCreateForm = useCallback(() => { + setShowCreateForm(false); + setCreateTitle(""); + setCreateGoal(""); + setRepoType("remote"); + setRepoUrl(""); + setRepoPath(""); + }, []); + const handleCreate = useCallback(async () => { if (!createTitle.trim() || !createGoal.trim()) return; @@ -91,18 +153,17 @@ function DirectivesContent() { title: createTitle.trim(), goal: createGoal.trim(), }; - if (createRepoUrl.trim()) { - data.repositoryUrl = createRepoUrl.trim(); + if (repoType === "remote" && repoUrl.trim()) { + data.repositoryUrl = repoUrl.trim(); + } else if (repoType === "local" && repoPath.trim()) { + data.localPath = repoPath.trim(); } const result = await saveDirective(data); if (result) { - setShowCreateForm(false); - setCreateTitle(""); - setCreateGoal(""); - setCreateRepoUrl(""); + resetCreateForm(); } - }, [createTitle, createGoal, createRepoUrl, saveDirective]); + }, [createTitle, createGoal, repoType, repoUrl, repoPath, saveDirective, resetCreateForm]); const handleDelete = useCallback( async (directiveId: string) => { @@ -118,7 +179,6 @@ function DirectivesContent() { async (directiveId: string) => { const ok = await startDirective(directiveId); if (ok) { - // Refresh the detail view const updated = await fetchDirective(directiveId); if (updated) { setSelectedDirective(updated); @@ -145,27 +205,30 @@ function DirectivesContent() { )} - {/* Create directive form */} + {/* Create directive modal */} {showCreateForm && (

New Directive

-
+
+ {/* Title */}
setCreateTitle(e.target.value)} className="w-full px-3 py-2 font-mono text-sm text-[#dbe7ff] bg-[#0d1b2d] border border-[#3f6fb3] focus:border-[#75aafc] outline-none" autoFocus />
+ + {/* Goal */}
-
-