/** * @file ReflogView.tsx * @description The read-only reflog of HEAD or of one local branch, paged * (GET /git/reflog): each entry's selector, what moved it (commit, rebase, * reset, checkout…), git's message, when, and the commit it points at — a * click opens that commit in the Changes panel. "Reset here" hands the entry * to the reset dialog, which is how a lost commit is brought back. * @author Nguyễn Ngọc Trí Vĩ */ import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { api, type GitTarget } from "../../../lib/api"; import { errText, gitRewrite, type ReflogEntry } from "../../../lib/gitRewrite"; import { BTN, ErrorLine, GitModal } from "./GitModal"; const PAGE = 50; function when(time: number | null, lang: string): string { if (!time) return ""; try { return new Date(time * 1000).toLocaleString(lang); } catch { return new Date(time * 1000).toISOString(); } } export function ReflogView({ target, onClose, onViewCommit, onReset, }: { target: GitTarget; onClose: () => void; /** Open one commit (the panel's commit view). */ onViewCommit?: (sha: string) => void; /** Open the reset dialog at this commit. */ onReset?: (entry: ReflogEntry) => void; }) { const { t, i18n } = useTranslation(["gitTools"]); const [ref, setRef] = useState("HEAD"); const [branches, setBranches] = useState([]); const [entries, setEntries] = useState(null); const [more, setMore] = useState(false); const [busy, setBusy] = useState(false); const [error, setError] = useState(null); const key = JSON.stringify(target); useEffect(() => { api.lanes .gitBranches(target) .then((b) => setBranches(b.branches ?? [])) .catch(() => setBranches([])); // eslint-disable-next-line react-hooks/exhaustive-deps }, [key]); const page = async (skip: number) => { setBusy(true); setError(null); try { const r = await gitRewrite.reflog(target, { ref, skip, limit: PAGE }); setEntries((prev) => (skip && prev ? [...prev, ...r.entries] : r.entries)); setMore(r.more); } catch (e) { setError(errText(e)); if (!skip) setEntries([]); } finally { setBusy(false); } }; useEffect(() => { setEntries(null); void page(0); // eslint-disable-next-line react-hooks/exhaustive-deps }, [key, ref]); return (

{t("reflog.hint")}

{entries == null ? (

{t("loading")}

) : !entries.length ? (

{t("reflog.empty")}

) : (
    {entries.map((e) => (
  • {e.selector} {e.action} {e.message || e.subject} {when(e.time, i18n.language)} {onViewCommit ? ( ) : ( {e.short} )} {onReset && ( )}
  • ))}
)} {more && ( )}
); }