import { useState, useEffect } from "react"; import { Icon } from "../../icon"; import { createInstance, startInstance, type ToolInstance, } from "../../../api/sessions"; import type { Project } from "../../../types"; import type { GitRepository } 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"; import { listWorkspaces, createWorkspace } from "../../../api/workspaces"; import type { Workspace } from "../../../types/workspace"; interface CreateSessionFormProps { projects: Project[]; repositories: GitRepository[]; toolTypes: ToolType[]; fixedProjectId?: string; fixedRepoId?: string; projectName?: string; repoName?: string; 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, 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 [sshKeys, setSshKeys] = useState([]); const [configProfiles, setConfigProfiles] = useState([]); const [selectedConfigProfile, setSelectedConfigProfile] = useState(""); const [selectedSshKeyIds, setSelectedSshKeyIds] = useState([]); const [workspaces, setWorkspaces] = useState([]); const [selectedWorkspaceId, setSelectedWorkspaceId] = useState(""); const [isLoadingWorkspaces, setIsLoadingWorkspaces] = useState(false); 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 workspaces when repository is selected useEffect(() => { const projectId = fixedProjectId || selectedProject; const repoId = fixedRepoId || selectedRepo; if (!projectId || !repoId) { setWorkspaces([]); setSelectedWorkspaceId(""); return; } const loadWorkspaces = async () => { setIsLoadingWorkspaces(true); try { const data = await listWorkspaces(projectId, repoId); setWorkspaces(data); if (data.length > 0) { setSelectedWorkspaceId(data[0].id); } else { // Auto-create a default workspace so the user can start a tool const workspace = await createWorkspace(projectId, repoId, { name: "default", branch: "main", }); setWorkspaces([workspace]); setSelectedWorkspaceId(workspace.id); } } catch (err) { setError( err instanceof Error ? err.message : "Failed to load workspaces", ); setWorkspaces([]); setSelectedWorkspaceId(""); } finally { setIsLoadingWorkspaces(false); } }; void loadWorkspaces(); }, [ fixedProjectId, selectedProject, fixedRepoId, selectedRepo, repositories, ]); // 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(""); setSelectedSshKeyIds([]); setSelectedConfigProfile(""); setWorkspaces([]); setSelectedWorkspaceId(""); }; 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; } setIsSubmitting(true); try { const workspaceId = selectedWorkspaceId || undefined; if (!workspaceId) { setError("No workspace available for the selected repository"); setIsSubmitting(false); return; } const instance = await createInstance( projectId, repoId, selectedToolType, displayName || undefined, workspaceId, 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 /> ) : ( )}
)} {/* Workspace */} {hasRepo && (
{isLoadingWorkspaces ? ( Loading workspaces... ) : workspaces.length === 0 ? ( No workspace available ) : ( )}
)} {/* 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
)} {/* Display Name */} {hasToolType && (
setDisplayName(e.target.value)} placeholder="My Development Environment" disabled={isSubmitting} />
)} {/* Error & Submit */} {error &&

{error}

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