import { useCallback, useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import { createConfigProfile, deleteConfigProfile, listConfigProfiles, previewConfigProfile, updateConfigProfile, type ConfigProfile, type CreateConfigProfileRequest, type ResolvedProfile, } from "../api/config_profiles"; import { Icon } from "../components/icon"; export const ConfigProfilesPage = () => { const navigate = useNavigate(); const [profiles, setProfiles] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [showForm, setShowForm] = useState(false); const [editingProfile, setEditingProfile] = useState(null); const [previewData, setPreviewData] = useState(null); const [previewingId, setPreviewingId] = useState(null); const [formData, setFormData] = useState({ name: "", description: "", env_vars: {}, runtime_hints: {}, mounts: [], files: {}, is_default: false, }); const loadProfiles = useCallback(async () => { try { setLoading(true); const data = await listConfigProfiles(); setProfiles(data); setError(null); } catch { setError("Failed to load config profiles"); } finally { setLoading(false); } }, []); useEffect(() => { void loadProfiles(); }, [loadProfiles]); const resetForm = () => { setFormData({ name: "", description: "", env_vars: {}, runtime_hints: {}, mounts: [], files: {}, is_default: false, }); setEditingProfile(null); setShowForm(false); }; const handleCreate = async (e: React.FormEvent) => { e.preventDefault(); if (!formData.name?.trim()) return; try { await createConfigProfile(formData); resetForm(); await loadProfiles(); } catch { setError("Failed to create config profile"); } }; const handleUpdate = async (e: React.FormEvent) => { e.preventDefault(); if (!editingProfile || !formData.name?.trim()) return; try { await updateConfigProfile(editingProfile.id, formData); resetForm(); await loadProfiles(); } catch { setError("Failed to update config profile"); } }; const handleDelete = async (id: string) => { if (!confirm("Are you sure you want to delete this config profile?")) return; try { await deleteConfigProfile(id); await loadProfiles(); } catch { setError("Failed to delete config profile"); } }; const startEdit = (profile: ConfigProfile) => { setEditingProfile(profile); setFormData({ name: profile.name, description: profile.description || undefined, project_id: profile.project_id || undefined, tool_type_id: profile.tool_type_id || undefined, env_vars: profile.env_vars, runtime_hints: profile.runtime_hints, mounts: profile.mounts, files: profile.files, is_default: profile.is_default, }); setShowForm(true); setPreviewData(null); setPreviewingId(null); }; const handlePreview = async (id: string) => { try { setPreviewingId(id); const data = await previewConfigProfile(id); setPreviewData(data); } catch { setError("Failed to preview config profile"); } finally { setPreviewingId(null); } }; const updateFormField = ( key: K, value: CreateConfigProfileRequest[K] ) => { setFormData((prev) => ({ ...prev, [key]: value })); }; const addEnvVar = () => { setFormData((prev) => ({ ...prev, env_vars: { ...prev.env_vars, "": "" }, })); }; const updateEnvVar = (oldKey: string, newKey: string, value: string) => { setFormData((prev) => { const envVars = { ...prev.env_vars }; if (oldKey !== newKey) { delete envVars[oldKey]; } envVars[newKey] = value; return { ...prev, env_vars: envVars }; }); }; const removeEnvVar = (key: string) => { setFormData((prev) => { const envVars = { ...prev.env_vars }; delete envVars[key]; return { ...prev, env_vars: envVars }; }); }; const addFile = () => { setFormData((prev) => ({ ...prev, files: { ...prev.files, "": "" }, })); }; const updateFile = (oldPath: string, newPath: string, content: string) => { setFormData((prev) => { const files = { ...prev.files }; if (oldPath !== newPath) { delete files[oldPath]; } files[newPath] = content; return { ...prev, files }; }); }; const removeFile = (path: string) => { setFormData((prev) => { const files = { ...prev.files }; delete files[path]; return { ...prev, files }; }); }; const addMount = () => { setFormData((prev) => ({ ...prev, mounts: [...(prev.mounts || []), { target: "/", mode: "rw", files: {} }], })); }; const updateMount = (index: number, updates: Partial) => { setFormData((prev) => { const mounts = [...(prev.mounts || [])]; mounts[index] = { ...mounts[index], ...updates }; return { ...prev, mounts }; }); }; const removeMount = (index: number) => { setFormData((prev) => { const mounts = [...(prev.mounts || [])]; mounts.splice(index, 1); return { ...prev, mounts }; }); }; const addMountFile = (mountIndex: number) => { setFormData((prev) => { const mounts = [...(prev.mounts || [])]; mounts[mountIndex] = { ...mounts[mountIndex], files: { ...mounts[mountIndex].files, "": "" }, }; return { ...prev, mounts }; }); }; const updateMountFile = ( mountIndex: number, oldPath: string, newPath: string, content: string ) => { setFormData((prev) => { const mounts = [...(prev.mounts || [])]; const files = { ...mounts[mountIndex].files }; if (oldPath !== newPath) { delete files[oldPath]; } files[newPath] = content; mounts[mountIndex] = { ...mounts[mountIndex], files }; return { ...prev, mounts }; }); }; const removeMountFile = (mountIndex: number, path: string) => { setFormData((prev) => { const mounts = [...(prev.mounts || [])]; const files = { ...mounts[mountIndex].files }; delete files[path]; mounts[mountIndex] = { ...mounts[mountIndex], files }; return { ...prev, mounts }; }); }; if (loading) return
Loading config profiles...
; return (

Settings

Config Profiles

{error &&
{error}
} {!showForm && ( )} {showForm && (

{editingProfile ? "Edit Profile" : "Create Profile"}

updateFormField("name", e.target.value)} placeholder="e.g., Development Environment" required />
updateFormField("description", e.target.value || undefined)} placeholder="Optional description" />
updateFormField("project_id", e.target.value || undefined)} placeholder="Optional project UUID" />
updateFormField("tool_type_id", e.target.value || undefined)} placeholder="Optional tool type UUID" />

Environment Variables

{Object.entries(formData.env_vars || {}).map(([key, value]) => (
updateEnvVar(key, e.target.value, value)} placeholder="VAR_NAME" /> updateEnvVar(key, key, e.target.value)} placeholder="value" />
))}

Runtime Hints