summaryrefslogtreecommitdiff
path: root/makima/frontend/src/routes
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-01-26 17:03:45 +0000
committerGitHub <noreply@github.com>2026-01-26 17:03:45 +0000
commit6328477bc459eca0243b685553dbd75b925fdc8a (patch)
treebf3eb29258244fea61daf93e128cd91540039dbc /makima/frontend/src/routes
parent1d83595f81fbfcc034c37c2260d695f094f5776e (diff)
downloadsoryu-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')
-rw-r--r--makima/frontend/src/routes/contracts.tsx52
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);
});
}