4 files changed,
54 insertions(+),
12 deletions(-)
Author:
Oleksandr Smirnov
olexsmir@gmail.com
Committed at:
2026-02-24 23:27:33 +0200
Change ID:
squqrynrrltxkpllnkmyksqmrlplnwpw
Parent:
b883855
M
internal/git/repo.go
@@ -11,6 +11,7 @@
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" + "github.com/go-git/go-git/v5/plumbing/storer" "github.com/go-git/go-git/v5/plumbing/transport" "github.com/go-git/go-git/v5/plumbing/transport/http" )@@ -129,21 +130,42 @@ HashShort: newShortHash(c.Hash),
} } -func (g *Repo) Commits() ([]*Commit, error) { +const CommitsPage = 150 + +// Commits returns [CommitsPage] commits after the given commit hash cursor. +// If after is empty, starts from HEAD. +func (g *Repo) Commits(after string) ([]*Commit, error) { if g.IsEmpty() { return []*Commit{}, nil } + from := g.h + if after != "" { + hash, err := g.r.ResolveRevision(plumbing.Revision(after)) + if err != nil { + return nil, fmt.Errorf("invalid cursor: %w", err) + } + from = *hash + } + ci, err := g.r.Log(&git.LogOptions{ - From: g.h, + From: from, Order: git.LogOrderCommitterTime, }) if err != nil { return nil, fmt.Errorf("commits from ref: %w", err) } - var commits []*Commit + // since after commit was shown on prev page, skip it + if after != "" { + ci.Next() + } + + commits := make([]*Commit, 0, CommitsPage) ci.ForEach(func(c *object.Commit) error { + if len(commits) == CommitsPage { + return storer.ErrStop + } commits = append(commits, newCommit(c)) return nil })
M
internal/handlers/repo.go
@@ -94,7 +94,7 @@ h.write500(w, err)
return } - p.Commits, err = repo.Commits() + p.Commits, err = repo.Commits("") if err != nil { h.write500(w, err) return@@ -239,14 +239,16 @@ h.templ(w, "repo_file", h.pageData(repo, p))
} type RepoLog struct { - Desc string - Commits []*git.Commit - Ref string + Desc string + Commits []*git.Commit + Ref string + NextAfter string } func (h *handlers) logHandler(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") ref := h.parseRef(r.PathValue("ref")) + after := r.URL.Query().Get("after") repo, err := h.openPublicRepo(name, ref) if err != nil {@@ -254,22 +256,30 @@ h.write404(w, err)
return } - commits, err := repo.Commits() + desc, err := repo.Description() if err != nil { h.write500(w, err) return } - desc, err := repo.Description() + commits, err := repo.Commits(after) if err != nil { h.write500(w, err) return } + // if we got full page of commits, we probably have more. + // NOTE: this has edge case, when last page has git.CommitsPage, "load more would be shown" + nextAfter := "" + if len(commits) == git.CommitsPage && len(commits) > 0 { + nextAfter = commits[len(commits)-1].HashShort + } + h.templ(w, "repo_log", h.pageData(repo, RepoLog{ - Desc: desc, - Commits: commits, - Ref: ref, + Desc: desc, + Ref: ref, + Commits: commits, + NextAfter: nextAfter, })) }
M
web/static/style.css
@@ -100,6 +100,11 @@ .nowrap { white-space: nowrap; }
.fill { width: 100%; } .muted { color: var(--gray); } +.center { + display: flex; + justify-content: center; +} + .size { text-align: right; } .mode, .size,
M
web/templates/repo_log.html
@@ -46,6 +46,11 @@ </tr>
{{ end }} </tbody> </table> + <div class="center"> + {{- if .P.NextAfter }} + <a href="?after={{ urlencode .P.NextAfter }}">[load more]</a> + {{- end }} + </div> </main> </body> </html>