github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/webui/src/pages/repositories/repository/commits/index.jsx (about) 1 import React, {useEffect, useState} from "react"; 2 import { useOutletContext } from "react-router-dom"; 3 import dayjs from "dayjs"; 4 import {BrowserIcon, LinkIcon, PackageIcon, PlayIcon} from "@primer/octicons-react"; 5 6 import {commits} from "../../../../lib/api"; 7 import ButtonGroup from "react-bootstrap/ButtonGroup"; 8 import Card from "react-bootstrap/Card"; 9 import ListGroup from "react-bootstrap/ListGroup"; 10 11 import { 12 ActionGroup, 13 ActionsBar, 14 ClipboardButton, 15 AlertError, 16 LinkButton, 17 Loading, RefreshButton 18 } from "../../../../lib/components/controls"; 19 import {CommitMessage} from "../../../../lib/components/repository/commits"; 20 import {useRefs} from "../../../../lib/hooks/repo"; 21 import {useAPIWithPagination} from "../../../../lib/hooks/api"; 22 import {Paginator} from "../../../../lib/components/pagination"; 23 import RefDropdown from "../../../../lib/components/repository/refDropdown"; 24 import {Link} from "../../../../lib/components/nav"; 25 import {useRouter} from "../../../../lib/hooks/router"; 26 import {RepoError} from "../error"; 27 28 29 const CommitWidget = ({ repo, commit }) => { 30 31 const buttonVariant = "outline-dark"; 32 33 return ( 34 <ListGroup.Item> 35 <div className="clearfix"> 36 <div className="float-start"> 37 <h6> 38 <Link href={{ 39 pathname: '/repositories/:repoId/commits/:commitId', 40 params: {repoId: repo.id, commitId: commit.id} 41 }}> 42 <CommitMessage commit={commit}/> 43 </Link> 44 </h6> 45 <p> 46 <small> 47 <strong>{commit.committer}</strong> committed at <strong>{dayjs.unix(commit.creation_date).format("MM/DD/YYYY HH:mm:ss")}</strong> ({dayjs.unix(commit.creation_date).fromNow()}) 48 </small> 49 </p> 50 </div> 51 <div className="float-end"> 52 <ButtonGroup className="commit-actions"> 53 <LinkButton 54 buttonVariant="outline-dark" 55 href={{ 56 pathname: '/repositories/:repoId/commits/:commitId', 57 params: {repoId: repo.id, commitId: commit.id} 58 }}> 59 <code>{commit.id.substr(0, 16)}</code> 60 </LinkButton> 61 <LinkButton 62 buttonVariant={buttonVariant} 63 href={{pathname: '/repositories/:repoId/actions', query: {commit: commit.id}, params: {repoId: repo.id}}} 64 tooltip="View Commit Action runs"> 65 <PlayIcon/> 66 </LinkButton> 67 <ClipboardButton variant={buttonVariant} text={commit.id} tooltip="Copy ID to clipboard"/> 68 <ClipboardButton variant={buttonVariant} text={`lakefs://${repo.id}/${commit.id}`} tooltip="Copy URI to clipboard" icon={<LinkIcon/>}/> 69 <ClipboardButton variant={buttonVariant} text={`s3://${repo.id}/${commit.id}`} tooltip="Copy S3 URI to clipboard" icon={<PackageIcon/>}/> 70 <LinkButton 71 buttonVariant="outline-dark" 72 href={{pathname: '/repositories/:repoId/objects', params: {repoId: repo.id}, query: {ref: commit.id}}} 73 tooltip="Browse objects at this commit"> 74 <BrowserIcon/> 75 </LinkButton> 76 77 </ButtonGroup> 78 </div> 79 </div> 80 </ListGroup.Item> 81 ); 82 } 83 84 85 const CommitsBrowser = ({ repo, reference, after, onPaginate, onSelectRef }) => { 86 87 const [refresh, setRefresh] = useState(true) 88 const { results, error, loading, nextPage } = useAPIWithPagination(async () => { 89 return commits.log(repo.id, reference.id, after) 90 }, [repo.id, reference.id, refresh, after]) 91 92 if (loading) return <Loading/> 93 if (error) return <AlertError error={error}/> 94 95 return ( 96 <div className="mb-5"> 97 98 <ActionsBar> 99 <ActionGroup orientation="left"> 100 <RefDropdown 101 repo={repo} 102 selected={(reference) ? reference : null} 103 withCommits={true} 104 withWorkspace={false} 105 selectRef={onSelectRef} 106 /> 107 </ActionGroup> 108 109 <ActionGroup orientation="right"> 110 <RefreshButton onClick={() => { setRefresh(!refresh); }}/> 111 </ActionGroup> 112 </ActionsBar> 113 114 <Card> 115 <ListGroup variant="flush"> 116 {results.map(commit => ( 117 <CommitWidget key={commit.id} repo={repo} commit={commit}/> 118 ))} 119 </ListGroup> 120 </Card> 121 <Paginator onPaginate={onPaginate} nextPage={nextPage} after={after}/> 122 </div> 123 ) 124 125 126 } 127 128 129 const CommitsContainer = () => { 130 const router = useRouter(); 131 const { after } = router.query; 132 const { repo, reference, loading ,error } = useRefs(); 133 134 if (loading) return <Loading/>; 135 if (error) return <RepoError error={error}/>; 136 137 const params = {repoId: repo.id}; 138 139 return ( 140 <CommitsBrowser 141 repo={repo} 142 reference={reference} 143 onSelectRef={ref => router.push({ 144 pathname: `/repositories/:repoId/commits`, 145 query: {ref: ref.id}, 146 params 147 })} 148 after={(after) ? after : ""} 149 onPaginate={after => router.push({ 150 pathname: `/repositories/:repoId/commits`, 151 query: {ref: reference.id, after}, 152 params 153 })} 154 /> 155 ); 156 }; 157 158 159 const RepositoryCommitsPage = () => { 160 const [setActivePage] = useOutletContext(); 161 useEffect(() => setActivePage('commits'), [setActivePage]); 162 return <CommitsContainer />; 163 }; 164 165 export default RepositoryCommitsPage;