import { useQuery, useQueryClient } from '@tanstack/react-query'; import { GitCommitVerticalIcon } from 'lucide-react'; import { ButtonLink } from '#/components/atoms/button-link.jsx'; import { Link } from '#/components/atoms/link.jsx'; import { AuthorFacepile } from '#/components/molecules/author-facepile.jsx'; import { Breadcrumbs } from '#/components/molecules/breadcrumbs.jsx'; import { CommitCheckStatus } from '#/components/molecules/commit-check-status.jsx'; import { EmptyState } from '#/components/molecules/empty-state.jsx'; import { ListBox } from '#/components/molecules/list-box.jsx'; import { ListSkeleton } from '#/components/molecules/list-skeleton.jsx'; import { PageHead } from '#/components/molecules/page-head.jsx'; import { PageNotice } from '#/components/molecules/page-notice.jsx'; import { ReadingRepo } from '#/components/molecules/reading-repo.jsx'; import { RefSelect } from '#/components/molecules/ref-select.jsx'; import { Screen } from '#/components/molecules/screen.jsx'; import { loadAuthors } from '#/lib/authors.js'; import { PULL_COMMIT_LIMIT, pullsHref } from '#/lib/collab.js'; import { timeAgo } from '#/lib/format.js'; import { isEmpty, repoRecord, repoSize } from '#/lib/git.js'; import { useNavigate } from '#/lib/navigation.jsx'; import { logKey, readLog } from '#/lib/source.js'; const LIMIT = PULL_COMMIT_LIMIT; /** * The commits on a ref, or the commits one pull request carries. * * A pull request's log is not its branch's: a branch reaches back through * everything it was cut from, and what somebody reading a pull request wants * is the commits it added. `base..tip` asks for those, from the copy that * holds them. */ export function CommitsPage({ repo, refName, path, range, from, space }) { const navigate = useNavigate(); const record = repoRecord(repo, space); // The tip of a range, which the way to its pull request names. const tip = range ? range.split('..')[1] : null; const pulls = useQueryClient().getQueryData(['pulls', repo, space ?? '']); const { data, error } = useQuery({ queryKey: logKey(repo, refName, range, from, space, path), enabled: Boolean(record) && !isEmpty(record) && !range, queryFn: () => readLog(repo, { refName, range, from, limit: LIMIT, space, path }), }); // The rows wait for the authors, so a face never lands after its row. const authors = useQuery({ queryKey: ['authors'], queryFn: loadAuthors, staleTime: Number.POSITIVE_INFINITY, }); const listed = data && (authors.isSuccess || authors.isError); if (!record) { return No such repository.; } const at = from ? `/${encodeURIComponent(from)}` : ''; const commitHref = (sha) => `/${encodeURIComponent(repo)}/commit${at}/${sha}`; // An empty repository has no ref for the log to read, so the listing // says so rather than asking the server for a ref that cannot exist. if (isEmpty(record) && !range) { return ( } title="No commits yet" description="This repository has no commits. Push the first one and it appears here." /> ); } // The page heads itself the way a forge heads a history: a title, and for // one path's history the path it is for. A pull request's commits carry // the way back to the pull request, which no tab above names. const refChip = ( {refName} ); const head = range ? ( The whole pull request as one diff } meta={Every commit the pull request carries.} /> ) : ( History for on {refChip} ) : ( on {refChip} ) } /> ); return ( {!range && (
navigate( `/${encodeURIComponent(repo)}/commits/${encodeURI(next)}${path ? `/${encodeURI(path)}` : ''}`, ) } />
)} {error && {error.message}} {!listed && !error && ( <>
)} {listed && (
    {data.commits.map((commit) => (
  • {commit.message.split('\n')[0]} {commit.sha.slice(0, 8)} {timeAgo(commit.committedAt)}
  • ))} {data.truncated && (
  • Showing the newest {LIMIT} commits.
  • )}
)}
); }