import { useState, useEffect } from "react"; import { Icon } from "../../icon"; import { createInstance, startInstance, type ToolInstance, } from "../../../api/sessions"; import type { Project } from "../../../types"; import { listRepositoryBranches, type GitRepository, type Branch, } from "../../../api/git-repositories"; import type { ToolType } from "../../../api/tool-types"; import { listSSHKeys, type SSHKey } from "../../../api/ssh-keys"; import { listConfigProfiles, type ConfigProfile, } from "../../../api/config-profiles"; interface CreateSessionFormProps { projects: Project[]; repositories: GitRepository[]; toolTypes: ToolType[]; fixedProjectId?: string; fixedRepoId?: string; projectName?: string; repoName?: string; showCloneMode?: boolean; showFixedFields?: boolean; onProjectChange?: (projectId: string) => void; onSuccess?: (instance: ToolInstance) => void; onCancel?: () => void; submitLabel?: string; className?: string; } export const CreateSessionForm = ({ projects, repositories, toolTypes, fixedProjectId, fixedRepoId, projectName, repoName, showCloneMode = true, showFixedFields = true, onProjectChange, onSuccess, onCancel, submitLabel = "Create Session", className = "", }: CreateSessionFormProps) => { const [selectedProject, setSelectedProject] = useState(fixedProjectId || ""); const [selectedRepo, setSelectedRepo] = useState(fixedRepoId || ""); const [selectedToolType, setSelectedToolType] = useState(""); const [displayName, setDisplayName] = useState(""); const [cloneMode, setCloneMode] = useState<"mount" | "clone">("mount"); const [branch, setBranch] = useState("main"); const [sshKeys, setSshKeys] = useState([]); const [configProfiles, setConfigProfiles] = useState([]); const [selectedConfigProfile, setSelectedConfigProfile] = useState(""); const [selectedSshKeyIds, setSelectedSshKeyIds] = useState([]); const [branches, setBranches] = useState([]); const [isLoadingBranches, setIsLoadingBranches] = useState(false); const [isCreatingNewBranch, setIsCreatingNewBranch] = useState(false); const [newBranchName, setNewBranchName] = useState(""); const [baseBranch, setBaseBranch] = useState(""); const [isSubmitting, setIsSubmitting] = useState(false); const [error, setError] = useState(null); // Load SSH keys useEffect(() => { const loadKeys = async () => { try { const keys = await listSSHKeys(); setSshKeys(keys); } catch { // ignore } }; void loadKeys(); }, []); // Load config profiles when tool type is selected useEffect(() => { const projectId = fixedProjectId || selectedProject; if (!selectedToolType || !projectId) { setConfigProfiles([]); setSelectedConfigProfile(""); return; } const loadProfiles = async () => { try { const profiles = await listConfigProfiles(projectId, selectedToolType); setConfigProfiles(profiles); // Auto-select default if available const defaultProfile = profiles.find((p) => p.is_default); if (defaultProfile) { setSelectedConfigProfile(defaultProfile.id); } } catch { // ignore } }; void loadProfiles(); }, [selectedToolType, selectedProject, fixedProjectId]); // Load branches when selected repo changes useEffect(() => { const projectId = fixedProjectId || selectedProject; if (!selectedRepo || !projectId || !showCloneMode) { setBranches([]); return; } const loadBranches = async () => { setIsLoadingBranches(true); try { const response = await listRepositoryBranches(projectId, selectedRepo); setBranches(response.branches); if (response.default_branch) { setBranch(response.default_branch); setBaseBranch(response.default_branch); } } catch { // ignore } finally { setIsLoadingBranches(false); } }; void loadBranches(); }, [selectedRepo, selectedProject, fixedProjectId, showCloneMode]); // Filter repositories by selected project const availableRepos = selectedProject ? repositories.filter((r) => r.project_id === selectedProject) : []; const resetForm = () => { if (!fixedProjectId) setSelectedProject(""); if (!fixedRepoId) setSelectedRepo(""); setSelectedToolType(""); setDisplayName(""); setCloneMode("mount"); setBranch("main"); setIsCreatingNewBranch(false); setNewBranchName(""); setBaseBranch(""); setBranches([]); setSelectedSshKeyIds([]); setSelectedConfigProfile(""); }; const handleSubmit = async (event: React.FormEvent) => { event.preventDefault(); setError(null); const projectId = fixedProjectId || selectedProject; const repoId = fixedRepoId || selectedRepo; if (!projectId || !repoId || !selectedToolType) { setError("Project, repository, and tool type are required"); return; } if (showCloneMode && cloneMode === "clone") { const repo = repositories.find((r) => r.id === repoId); if (!repo?.ssh_key_id) { setError("Repository must have an SSH key assigned for clone mode"); return; } } setIsSubmitting(true); try { const instance = await createInstance( projectId, repoId, selectedToolType, displayName || undefined, showCloneMode ? cloneMode : undefined, showCloneMode && cloneMode === "clone" ? isCreatingNewBranch ? baseBranch : branch : undefined, showCloneMode && cloneMode === "clone" && isCreatingNewBranch ? newBranchName : undefined, selectedConfigProfile || undefined, selectedSshKeyIds.length > 0 ? selectedSshKeyIds : undefined, ); await startInstance( projectId, repoId, instance.id, selectedConfigProfile || undefined, selectedSshKeyIds.length > 0 ? selectedSshKeyIds : undefined, ); resetForm(); onSuccess?.(instance); } catch { setError("Failed to create session"); } finally { setIsSubmitting(false); } }; const hasProject = !!(fixedProjectId || selectedProject); const hasRepo = !!(fixedRepoId || selectedRepo); const hasToolType = !!selectedToolType; return (
{/* Project */}
{fixedProjectId && showFixedFields ? ( p.id === fixedProjectId)?.name || "" } disabled readOnly /> ) : ( )}
{/* Repository */} {hasProject && (
{fixedRepoId && showFixedFields ? ( r.id === fixedRepoId)?.name || "" } disabled readOnly /> ) : ( )}
)} {/* Tool Type */} {hasRepo && (
)} {/* Config Profile */} {hasToolType && (
)} {/* SSH Keys */} {hasToolType && (
{sshKeys.length === 0 && ( No SSH keys configured. )} {sshKeys.map((key) => ( ))}
Selected keys will be mounted into the container at ~/.ssh
)} {/* Clone Mode & Branch */} {showCloneMode && hasToolType && (
{cloneMode === "clone" && ( <> {isCreatingNewBranch && ( <> )} {selectedRepo && (
{(() => { const repo = repositories.find( (r) => r.id === selectedRepo, ); if (!repo) return null; if (repo.ssh_key_id) { const key = sshKeys.find( (k) => k.id === repo.ssh_key_id, ); return ( SSH key: {key?.name || "Assigned"} ); } return ( No SSH key assigned to this repository. Clone mode requires an SSH key. ); })()}
)} )}
)} {/* Display Name */} {hasToolType && (
setDisplayName(e.target.value)} placeholder="My Development Environment" disabled={isSubmitting} />
)} {/* Error & Submit */} {error &&

{error}

} {hasToolType && (
{onCancel && ( )}
)}
); };