import { useEffect, useRef, useState } from "react"; import type { GitRepositoryCreate, URLParseResult, } from "../../../types/git-repository"; import { createRepository, parseGitUrl } from "../../../api/git-repositories"; import { Icon } from "../../ui/Icon"; type CreateMode = "clone" | "blank"; type UrlValidationStatus = | "idle" | "validating" | "valid" | "needs-parsing" | "invalid"; interface RepositoryCreateDialogProps { projectId: string; open: boolean; title: string; onClose: () => void; onCreated: () => Promise | void; } export const RepositoryCreateDialog = ({ projectId, open, title, onClose, onCreated, }: RepositoryCreateDialogProps) => { const [createMode, setCreateMode] = useState("clone"); const [formName, setFormName] = useState(""); const [owner, setOwner] = useState(""); const [repoName, setRepoName] = useState(""); const [advancedUrl, setAdvancedUrl] = useState(""); const [useAdvancedUrl, setUseAdvancedUrl] = useState(false); const [formError, setFormError] = useState(null); const [urlValidation, setUrlValidation] = useState<{ status: UrlValidationStatus; result: URLParseResult | null; }>({ status: "idle", result: null }); const debounceTimer = useRef | null>(null); useEffect(() => { if (!open && debounceTimer.current) { clearTimeout(debounceTimer.current); debounceTimer.current = null; } }, [open]); useEffect(() => { if (!open) return; if (!useAdvancedUrl) { setUrlValidation({ status: "idle", result: null }); return; } if (debounceTimer.current) { clearTimeout(debounceTimer.current); } if (!advancedUrl.trim()) { setUrlValidation({ status: "idle", result: null }); return; } setUrlValidation({ status: "validating", result: null }); debounceTimer.current = setTimeout(async () => { try { const result = await parseGitUrl(advancedUrl.trim()); if (result.is_valid_clone_url) { setUrlValidation({ status: "valid", result }); } else if (result.needs_parsing) { setUrlValidation({ status: "needs-parsing", result }); } else { setUrlValidation({ status: "invalid", result }); } } catch { setUrlValidation({ status: "invalid", result: null }); } }, 300); return () => { if (debounceTimer.current) { clearTimeout(debounceTimer.current); } }; }, [advancedUrl, open, useAdvancedUrl]); const resetForm = () => { setCreateMode("clone"); setFormName(""); setOwner(""); setRepoName(""); setAdvancedUrl(""); setUseAdvancedUrl(false); setFormError(null); setUrlValidation({ status: "idle", result: null }); }; const handleClose = () => { resetForm(); onClose(); }; const handleSubmit = async (event: React.FormEvent) => { event.preventDefault(); setFormError(null); if (!formName.trim()) { setFormError("Repository name is required"); return; } try { const input: GitRepositoryCreate = { name: formName.trim(), remote_url: undefined, }; if (createMode === "clone") { if (useAdvancedUrl) { if (!advancedUrl.trim()) { setFormError("Remote URL is required for advanced cloning"); return; } input.remote_url = advancedUrl.trim(); } else { if (!owner.trim() || !repoName.trim()) { setFormError("Owner and repository name are required"); return; } input.remote_url = `git@git.commumedia.org:${owner.trim()}/${repoName.trim()}.git`; } } await createRepository(projectId, input); handleClose(); await onCreated(); } catch (error: unknown) { const response = error as { response?: { data?: { detail?: string } } }; const detail = response.response?.data?.detail; setFormError( typeof detail === "string" ? detail : "Failed to create repository", ); } }; const handleUseSuggestedUrl = () => { if (urlValidation.result?.base_url) { setAdvancedUrl(urlValidation.result.base_url); setUrlValidation({ status: "idle", result: null }); setFormError(null); } }; const getUrlInputClass = () => { switch (urlValidation.status) { case "valid": return "valid-url"; case "needs-parsing": return "needs-parsing-url"; case "invalid": return "invalid-url"; default: return ""; } }; if (!open) return null; return (

{title}

Clone an existing repository from git.commumedia.org, or create a blank bare repo here.

{createMode === "clone" && !useAdvancedUrl && ( <>

SSH target: git@git.commumedia.org:{owner || "owner"}/ {repoName || "repo"}.git

)} {createMode === "clone" && useAdvancedUrl && ( )} {formError && (

{formError}

)}
); };