import { useCallback, useEffect, useState } from "react"; import { useNavigate, useParams } from "react-router-dom"; import { getCommitDetail, getRepositoryHistory, type CommitDetail, type CommitHistoryEntry } from "../api/git_repositories"; import { Icon } from "../components/icon"; export const GitHistoryPage = () => { const { projectId, repoId } = useParams<{ projectId: string; repoId: string }>(); const navigate = useNavigate(); const [commits, setCommits] = useState([]); const [selectedCommit, setSelectedCommit] = useState(null); const [commitDetail, setCommitDetail] = useState(null); const [branches, setBranches] = useState([]); const [selectedBranch, setSelectedBranch] = useState(""); const [status, setStatus] = useState<"loading" | "ready" | "error">("loading"); const [detailStatus, setDetailStatus] = useState<"idle" | "loading" | "ready" | "error">("idle"); const loadHistory = useCallback(async () => { if (!projectId || !repoId) return; setStatus("loading"); try { const data = await getRepositoryHistory(projectId, repoId, selectedBranch || undefined, 10000); setCommits(data.commits); setBranches(data.branches); if (data.branches.length > 0 && !selectedBranch) { setSelectedBranch(data.branches[0]); } setStatus("ready"); } catch { setStatus("error"); } }, [projectId, repoId, selectedBranch]); useEffect(() => { void loadHistory(); }, [loadHistory]); const handleCommitClick = async (hash: string) => { if (!projectId || !repoId) return; setSelectedCommit(hash); setDetailStatus("loading"); try { const detail = await getCommitDetail(projectId, repoId, hash); setCommitDetail(detail); setDetailStatus("ready"); } catch { setDetailStatus("error"); } }; const handleCloseDetail = () => { setSelectedCommit(null); setCommitDetail(null); setDetailStatus("idle"); }; const formatDate = (dateStr: string) => { return new Date(dateStr).toLocaleString(); }; if (status === "loading") { return (

Loading commit history...

); } if (status === "error") { return (

Failed to load commit history

); } return (

Commit History

{commits.length} commits

{branches.length > 0 && ( )}
{commits.map((commit) => (
void handleCommitClick(commit.hash)} role="button" tabIndex={0} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { void handleCommitClick(commit.hash); } }} >
{commit.graph_symbol}
{commit.short_hash} {commit.refs.length > 0 && ( {commit.refs.map((ref) => ( {ref} ))} )}

{commit.message.split("\n")[0]}

{commit.author_name} {formatDate(commit.author_date)}
))}
{selectedCommit && (

Commit Details

{detailStatus === "loading" &&

Loading details...

} {detailStatus === "error" && (

Failed to load commit details

)} {detailStatus === "ready" && commitDetail && (

{commitDetail.hash}

{commitDetail.message}

Author

{commitDetail.author_name} <{commitDetail.author_email}>

{formatDate(commitDetail.author_date)}

Committer

{commitDetail.committer_name} <{commitDetail.committer_email}>

{formatDate(commitDetail.committer_date)}

Stats

{commitDetail.stats.files_changed} Files
+{commitDetail.stats.additions} Additions
-{commitDetail.stats.deletions} Deletions
{commitDetail.parents.length > 0 && (

Parents

{commitDetail.parents.map((parent) => ( {parent.substring(0, 8)} ))}
)} {commitDetail.diff && (

Diff

{commitDetail.diff}
)}
)}
)}
); };