From 9aadbc7958d39d181c0dd0600e2b7c30bb6c391a Mon Sep 17 00:00:00 2001 From: soryu Date: Sat, 14 Feb 2026 21:29:26 +0000 Subject: Makima system improvements: Orders, directive questions, PR creation fix, bug fixes (#62) * feat: soryu-co/soryu - makima: Fix directive goal update bug - stale closure issue * WIP: heartbeat checkpoint * WIP: heartbeat checkpoint * feat: soryu-co/soryu - makima: Create Orders database schema and backend API * feat: soryu-co/soryu - makima: Fix task Claude instance not receiving user inputs from input box * WIP: heartbeat checkpoint * feat: soryu-co/soryu - makima: Build Orders frontend page replacing the Board page * WIP: heartbeat checkpoint * WIP: heartbeat checkpoint * feat: soryu-co/soryu - makima: Fix directive PR creation system --- makima/frontend/src/routes/directives.tsx | 3 +- makima/frontend/src/routes/mesh.tsx | 2 +- makima/frontend/src/routes/orders.tsx | 238 ++++++++++++++++++++++++++++ makima/frontend/src/routes/workflow.tsx | 250 ------------------------------ 4 files changed, 241 insertions(+), 252 deletions(-) create mode 100644 makima/frontend/src/routes/orders.tsx delete mode 100644 makima/frontend/src/routes/workflow.tsx (limited to 'makima/frontend/src/routes') diff --git a/makima/frontend/src/routes/directives.tsx b/makima/frontend/src/routes/directives.tsx index ca4437c..643cfee 100644 --- a/makima/frontend/src/routes/directives.tsx +++ b/makima/frontend/src/routes/directives.tsx @@ -12,7 +12,7 @@ export default function DirectivesPage() { 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, cleanupTasks } = useDirective(selectedId); + const { directive, refresh: refreshDetail, update, start, pause, advance, completeStep, failStep, skipStep, updateGoal, cleanupTasks } = useDirective(selectedId); const [showCreate, setShowCreate] = useState(false); const [newTitle, setNewTitle] = useState(""); @@ -207,6 +207,7 @@ export default function DirectivesPage() { onFailStep={failStep} onSkipStep={skipStep} onUpdateGoal={updateGoal} + onUpdate={update} onDelete={handleDelete} onRefresh={refreshDetail} onCleanupTasks={cleanupTasks} diff --git a/makima/frontend/src/routes/mesh.tsx b/makima/frontend/src/routes/mesh.tsx index cb4a77c..1d1db84 100644 --- a/makima/frontend/src/routes/mesh.tsx +++ b/makima/frontend/src/routes/mesh.tsx @@ -852,7 +852,7 @@ export default function MeshPage() {
{ setViewingSubtaskId(null); diff --git a/makima/frontend/src/routes/orders.tsx b/makima/frontend/src/routes/orders.tsx new file mode 100644 index 0000000..735c557 --- /dev/null +++ b/makima/frontend/src/routes/orders.tsx @@ -0,0 +1,238 @@ +import { useState, useEffect } from "react"; +import { useParams, useNavigate } from "react-router"; +import { Masthead } from "../components/Masthead"; +import { OrderList } from "../components/orders/OrderList"; +import { OrderDetail } from "../components/orders/OrderDetail"; +import { useOrders, useOrder } from "../hooks/useOrders"; +import { useDirectives } from "../hooks/useDirectives"; +import { useAuth } from "../contexts/AuthContext"; +import type { OrderStatus, OrderType, OrderPriority } from "../lib/api"; + +export default function OrdersPage() { + const { isAuthenticated, isAuthConfigured, isLoading: authLoading } = useAuth(); + const navigate = useNavigate(); + const { id: selectedId } = useParams<{ id: string }>(); + + const [statusFilter, setStatusFilter] = useState(undefined); + const [typeFilter, setTypeFilter] = useState(undefined); + const { orders, loading: listLoading, create, refresh: refreshList } = useOrders(statusFilter, typeFilter); + const { order, refresh: refreshDetail, update, remove: removeOrder, linkDirective, linkContract, convertToStep } = useOrder(selectedId); + const { directives } = useDirectives(); + + const [showCreate, setShowCreate] = useState(false); + const [newTitle, setNewTitle] = useState(""); + const [newDesc, setNewDesc] = useState(""); + const [newPriority, setNewPriority] = useState("medium"); + const [newType, setNewType] = useState("feature"); + + useEffect(() => { + if (!authLoading && isAuthConfigured && !isAuthenticated) { + navigate("/login"); + } + }, [authLoading, isAuthConfigured, isAuthenticated, navigate]); + + if (authLoading) { + return ( +
+ +
+

Loading...

+
+
+ ); + } + + const handleCreate = async () => { + if (!newTitle.trim()) return; + try { + const o = await create({ + title: newTitle.trim(), + description: newDesc.trim() || undefined, + priority: newPriority, + orderType: newType, + }); + setShowCreate(false); + setNewTitle(""); + setNewDesc(""); + setNewPriority("medium"); + setNewType("feature"); + navigate(`/orders/${o.id}`); + } catch (e) { + console.error("Failed to create order:", e); + } + }; + + const handleDelete = async () => { + if (!selectedId) return; + if (!window.confirm("Delete this order?")) return; + try { + await removeOrder(); + await refreshList(); + navigate("/orders"); + } catch (e) { + console.error("Failed to delete:", e); + } + }; + + const handleUpdate = async (req: Parameters[0]) => { + await update(req); + await refreshList(); + }; + + const handleLinkDirective = async (directiveId: string) => { + await linkDirective(directiveId); + await refreshList(); + }; + + const handleLinkContract = async (contractId: string) => { + await linkContract(contractId); + await refreshList(); + }; + + const handleConvertToStep = async (directiveId: string) => { + await convertToStep(directiveId); + await refreshList(); + }; + + const priorityOptions: { value: OrderPriority; label: string }[] = [ + { value: "critical", label: "Critical" }, + { value: "high", label: "High" }, + { value: "medium", label: "Medium" }, + { value: "low", label: "Low" }, + { value: "none", label: "None" }, + ]; + + const typeOptions: { value: OrderType; label: string }[] = [ + { value: "feature", label: "Feature" }, + { value: "bug", label: "Bug" }, + { value: "spike", label: "Spike" }, + { value: "chore", label: "Chore" }, + { value: "improvement", label: "Improvement" }, + ]; + + return ( +
+ +
+ {/* Left: List */} +
+ navigate(`/orders/${id}`)} + onCreate={() => setShowCreate(true)} + statusFilter={statusFilter} + onStatusFilter={setStatusFilter} + typeFilter={typeFilter} + onTypeFilter={setTypeFilter} + /> +
+ + {/* Right: Detail or Create */} +
+ {showCreate ? ( +
+

+ New Order +

+
+
+ + setNewTitle(e.target.value)} + placeholder="Order 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" + onKeyDown={(e) => { + if (e.key === "Enter" && newTitle.trim()) handleCreate(); + }} + /> +
+
+ +