diff options
| author | soryu <soryu@soryu.co> | 2026-01-26 17:03:45 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-26 17:03:45 +0000 |
| commit | 6328477bc459eca0243b685553dbd75b925fdc8a (patch) | |
| tree | bf3eb29258244fea61daf93e128cd91540039dbc /makima/frontend/src/routes/contracts.tsx | |
| parent | 1d83595f81fbfcc034c37c2260d695f094f5776e (diff) | |
| download | soryu-6328477bc459eca0243b685553dbd75b925fdc8a.tar.gz soryu-6328477bc459eca0243b685553dbd75b925fdc8a.zip | |
Add dynamic contract type templates with user customization (#33)
- Add 'execute' contract type as a built-in template in backend
- Fix API response field name mismatch (types -> contractTypes)
- Remove duplicate ContractTypeTemplate definition in api.ts
- Merge built-in types from API with user templates from localStorage
- User templates created in the Templates page now appear in contract creation
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'makima/frontend/src/routes/contracts.tsx')
| -rw-r--r-- | makima/frontend/src/routes/contracts.tsx | 52 |
1 files changed, 47 insertions, 5 deletions
diff --git a/makima/frontend/src/routes/contracts.tsx b/makima/frontend/src/routes/contracts.tsx index 4f74692..36eb980 100644 --- a/makima/frontend/src/routes/contracts.tsx +++ b/makima/frontend/src/routes/contracts.tsx @@ -93,19 +93,49 @@ function ContractsPageContent() { const [contractTypes, setContractTypes] = useState<ContractTypeTemplate[]>([]); const [contractTypesLoading, setContractTypesLoading] = useState(false); - // Fetch contract types when modal opens + // Fetch contract types when modal opens - merges built-in types with user templates useEffect(() => { if (isCreating) { setContractTypesLoading(true); + + // Load user templates from localStorage + const loadUserTemplates = (): ContractTypeTemplate[] => { + try { + const saved = localStorage.getItem("makima_contract_templates"); + if (saved) { + const templates = JSON.parse(saved); + // Convert user templates to ContractTypeTemplate format, excluding built-ins + return templates + .filter((t: { isBuiltIn?: boolean }) => !t.isBuiltIn) + .map((t: { id: string; name: string; description: string; phases: { id: string }[] }) => ({ + id: t.id, + name: t.name, + description: t.description, + phases: t.phases.map((p: { id: string }) => p.id) as ContractPhase[], + defaultPhase: (t.phases[0]?.id || "execute") as ContractPhase, + isBuiltin: false, + })); + } + } catch { + // Ignore localStorage errors + } + return []; + }; + listContractTypes() .then((res) => { - setContractTypes(res.types); + // Merge built-in types from API with user templates from localStorage + const userTemplates = loadUserTemplates(); + // Filter out any user templates that have the same ID as built-in types + const builtinIds = new Set(res.contractTypes.map(t => t.id)); + const uniqueUserTemplates = userTemplates.filter(t => !builtinIds.has(t.id)); + setContractTypes([...res.contractTypes, ...uniqueUserTemplates]); setContractTypesLoading(false); }) .catch((err) => { console.error("Failed to fetch contract types:", err); - // Fall back to built-in types - setContractTypes([ + // Fall back to built-in types + user templates + const builtinTypes: ContractTypeTemplate[] = [ { id: "simple", name: "Simple", @@ -122,7 +152,19 @@ function ContractsPageContent() { defaultPhase: "research", isBuiltin: true, }, - ]); + { + id: "execute", + name: "Execute", + description: "Execute only: Minimal workflow for immediate task execution", + phases: ["execute"], + defaultPhase: "execute", + isBuiltin: true, + }, + ]; + const userTemplates = loadUserTemplates(); + const builtinIds = new Set(builtinTypes.map(t => t.id)); + const uniqueUserTemplates = userTemplates.filter(t => !builtinIds.has(t.id)); + setContractTypes([...builtinTypes, ...uniqueUserTemplates]); setContractTypesLoading(false); }); } |
