import { useState, useCallback, useEffect } from "react"; 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() { const { isAuthenticated, isAuthConfigured, isLoading: authLoading } = useAuth(); const navigate = useNavigate(); // Redirect to login if not authenticated (when auth is configured) useEffect(() => { if (!authLoading && isAuthConfigured && !isAuthenticated) { navigate("/login"); } }, [authLoading, isAuthConfigured, isAuthenticated, navigate]); if (authLoading) { return (

Loading...

); } if (isAuthConfigured && !isAuthenticated) { return null; } return ; } function DirectivesContent() { const { id } = useParams<{ id?: string }>(); const navigate = useNavigate(); const { directives, loading, error, fetchDirective, saveDirective, removeDirective, startDirective, } = useDirectives(); const [selectedDirective, setSelectedDirective] = useState(null); const [detailLoading, setDetailLoading] = useState(false); const [showCreateForm, setShowCreateForm] = useState(false); const [createTitle, setCreateTitle] = useState(""); const [createGoal, setCreateGoal] = 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(() => { if (id) { setDetailLoading(true); fetchDirective(id).then((d) => { setSelectedDirective(d); setDetailLoading(false); }); } else { setSelectedDirective(null); } }, [id, fetchDirective]); const handleSelect = useCallback( (directiveId: string) => { navigate(`/directives/${directiveId}`); }, [navigate] ); const handleBack = useCallback(() => { navigate("/directives"); }, [navigate]); const resetCreateForm = useCallback(() => { setShowCreateForm(false); setCreateTitle(""); setCreateGoal(""); setRepoType("remote"); setRepoUrl(""); setRepoPath(""); }, []); const handleCreate = useCallback(async () => { if (!createTitle.trim() || !createGoal.trim()) return; const data: CreateDirectiveRequest = { title: createTitle.trim(), goal: createGoal.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) { resetCreateForm(); } }, [createTitle, createGoal, repoType, repoUrl, repoPath, saveDirective, resetCreateForm]); const handleDelete = useCallback( async (directiveId: string) => { const ok = await removeDirective(directiveId); if (ok && id === directiveId) { navigate("/directives"); } }, [removeDirective, id, navigate] ); const handleStart = useCallback( async (directiveId: string) => { const ok = await startDirective(directiveId); if (ok) { const updated = await fetchDirective(directiveId); if (updated) { setSelectedDirective(updated); } } }, [startDirective, fetchDirective] ); const handleRefresh = useCallback( (updated: DirectiveWithChains) => { setSelectedDirective(updated); }, [] ); return (
{error && (
{error}
)} {/* 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 */}