From b58a7a92f86784620bd5eb214d7f191c6f68f4d3 Mon Sep 17 00:00:00 2001 From: soryu Date: Sun, 25 Jan 2026 02:55:45 +0000 Subject: [WIP] Heartbeat checkpoint - 2026-01-25 02:55:45 UTC --- makima/frontend/src/routes/contracts.tsx | 121 +++++++++++++++++++++---------- 1 file changed, 82 insertions(+), 39 deletions(-) (limited to 'makima/frontend/src/routes') diff --git a/makima/frontend/src/routes/contracts.tsx b/makima/frontend/src/routes/contracts.tsx index 6acda29..aa5bf3d 100644 --- a/makima/frontend/src/routes/contracts.tsx +++ b/makima/frontend/src/routes/contracts.tsx @@ -6,7 +6,12 @@ import { ContractDetail } from "../components/contracts/ContractDetail"; import { DirectoryInput } from "../components/mesh/DirectoryInput"; import { useContracts } from "../hooks/useContracts"; import { useAuth } from "../contexts/AuthContext"; -import { createTask, getDaemonDirectories, getRepositorySuggestions } from "../lib/api"; +import { + createTask, + getDaemonDirectories, + getRepositorySuggestions, + listContractTypes, +} from "../lib/api"; import type { ContractWithRelations, ContractSummary, @@ -17,8 +22,8 @@ import type { RepositorySourceType, DaemonDirectory, RepositoryHistoryEntry, + ContractTypeTemplate, } from "../lib/api"; -import { getValidPhases, getDefaultPhase } from "../lib/api"; export default function ContractsPage() { const { isAuthenticated, isAuthConfigured, isLoading: authLoading } = useAuth(); @@ -85,6 +90,43 @@ function ContractsPageContent() { const [suggestedDirectories, setSuggestedDirectories] = useState([]); const [repoSuggestions, setRepoSuggestions] = useState([]); const [showRepoSuggestions, setShowRepoSuggestions] = useState(false); + const [contractTypes, setContractTypes] = useState([]); + const [contractTypesLoading, setContractTypesLoading] = useState(false); + + // Fetch contract types when modal opens + useEffect(() => { + if (isCreating) { + setContractTypesLoading(true); + listContractTypes() + .then((res) => { + setContractTypes(res.types); + setContractTypesLoading(false); + }) + .catch((err) => { + console.error("Failed to fetch contract types:", err); + // Fall back to built-in types + setContractTypes([ + { + id: "simple", + name: "Simple", + description: "Plan \u2192 Execute: Simple workflow with a plan document", + phases: ["plan", "execute"], + defaultPhase: "plan", + isBuiltin: true, + }, + { + id: "specification", + name: "Specification", + description: "Research \u2192 Specify \u2192 Plan \u2192 Execute \u2192 Review: Full specification-driven development with TDD", + phases: ["research", "specify", "plan", "execute", "review"], + defaultPhase: "research", + isBuiltin: true, + }, + ]); + setContractTypesLoading(false); + }); + } + }, [isCreating]); // Fetch repository suggestions when modal opens and repo type changes useEffect(() => { @@ -170,11 +212,15 @@ function ContractsPageContent() { setCreateError(null); + // Get default phase from contract types or fall back to static function + const selectedType = contractTypes.find((t) => t.id === contractType); + const defaultPhaseForType = selectedType?.defaultPhase || (contractType === "simple" ? "plan" : "research"); + const data: CreateContractRequest = { name: newContractName.trim(), description: newContractDescription.trim() || undefined, contractType: contractType, - initialPhase: initialPhase !== getDefaultPhase(contractType) ? initialPhase : undefined, + initialPhase: initialPhase !== defaultPhaseForType ? initialPhase : undefined, }; try { @@ -224,6 +270,7 @@ function ContractsPageContent() { newContractName, newContractDescription, contractType, + contractTypes, initialPhase, repoType, repoName, @@ -514,41 +561,37 @@ function ContractsPageContent() { -
- - -
-

- {contractType === "simple" - ? "Plan → Execute: Simple workflow with a plan document" - : "Research → Specify → Plan → Execute → Review: Full specification-driven development with TDD"} -

+ {contractTypesLoading ? ( +
+ Loading contract types... +
+ ) : ( + <> +
+ {contractTypes.map((type) => ( + + ))} +
+

+ {contractTypes.find((t) => t.id === contractType)?.description || + "Select a contract type"} +

+ + )} {/* Starting Phase */} @@ -561,7 +604,7 @@ function ContractsPageContent() { onChange={(e) => setInitialPhase(e.target.value as ContractPhase)} className="w-full px-3 py-2 bg-[#0d1b2d] border border-[#3f6fb3] text-[#dbe7ff] font-mono text-sm focus:outline-none focus:border-[#75aafc]" > - {getValidPhases(contractType).map((phase) => ( + {(contractTypes.find((t) => t.id === contractType)?.phases || []).map((phase) => ( -- cgit v1.2.3