From 8c23b3ab6f7fabca01b0468911bae073aa5ced32 Mon Sep 17 00:00:00 2001 From: soryu Date: Mon, 9 Feb 2026 00:11:51 +0000 Subject: Add new directive mechanism v3 --- makima/frontend/src/routes/directives.tsx | 168 ++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 makima/frontend/src/routes/directives.tsx (limited to 'makima/frontend/src/routes') diff --git a/makima/frontend/src/routes/directives.tsx b/makima/frontend/src/routes/directives.tsx new file mode 100644 index 0000000..82e5d48 --- /dev/null +++ b/makima/frontend/src/routes/directives.tsx @@ -0,0 +1,168 @@ +import { useState, 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 { useDirectives, useDirective } from "../hooks/useDirectives"; +import { useAuth } from "../contexts/AuthContext"; + +export default function DirectivesPage() { + const { isAuthenticated, isAuthConfigured, isLoading: authLoading } = useAuth(); + const navigate = useNavigate(); + const { id: selectedId } = useParams<{ id: string }>(); + const { directives, loading: listLoading, create, remove } = useDirectives(); + const { directive, refresh: refreshDetail, start, pause, advance, completeStep, failStep, skipStep, updateGoal } = useDirective(selectedId); + + const [showCreate, setShowCreate] = useState(false); + const [newTitle, setNewTitle] = useState(""); + const [newGoal, setNewGoal] = useState(""); + const [newRepoUrl, setNewRepoUrl] = useState(""); + + useEffect(() => { + if (!authLoading && isAuthConfigured && !isAuthenticated) { + navigate("/login"); + } + }, [authLoading, isAuthConfigured, isAuthenticated, navigate]); + + if (authLoading) { + return ( +
+ +
+

Loading...

+
+
+ ); + } + + const handleCreate = async () => { + if (!newTitle.trim() || !newGoal.trim()) return; + try { + const d = await create({ + title: newTitle.trim(), + goal: newGoal.trim(), + repositoryUrl: newRepoUrl.trim() || undefined, + }); + setShowCreate(false); + setNewTitle(""); + setNewGoal(""); + setNewRepoUrl(""); + navigate(`/directives/${d.id}`); + } catch (e) { + console.error("Failed to create directive:", e); + } + }; + + const handleDelete = async () => { + if (!selectedId) return; + if (!window.confirm("Delete this directive?")) return; + try { + await remove(selectedId); + navigate("/directives"); + } catch (e) { + console.error("Failed to delete:", e); + } + }; + + return ( +
+ +
+ {/* Left: List */} +
+ navigate(`/directives/${id}`)} + onCreate={() => setShowCreate(true)} + /> +
+ + {/* Right: Detail or Create */} +
+ {showCreate ? ( +
+

+ New Directive +

+
+
+ + setNewTitle(e.target.value)} + placeholder="Project title..." + className="w-full bg-[#0a1628] border border-[rgba(117,170,252,0.2)] rounded px-2 py-1.5 text-[12px] font-mono text-white" + /> +
+
+ +