From 66cb3dd7f176747917bcb68a292e4b90c31b3935 Mon Sep 17 00:00:00 2001 From: Will Date: Sat, 9 May 2026 17:01:33 +0100 Subject: [PATCH] appview/repo: show number of forks on repo and link to page of forks Signed-off-by: Will --- appview/db/repos.go | 10 ++++++ appview/pages/pages.go | 14 ++++++++ appview/pages/templates/layouts/repobase.html | 27 +++++++++----- appview/pages/templates/repo/forks.html | 35 +++++++++++++++++++ appview/repo/repo.go | 33 +++++++++++++++++ appview/repo/router.go | 1 + 6 files changed, 111 insertions(+), 9 deletions(-) create mode 100644 appview/pages/templates/repo/forks.html diff --git a/appview/db/repos.go b/appview/db/repos.go index c68df9e8..c1345a2c 100644 --- a/appview/db/repos.go +++ b/appview/db/repos.go @@ -878,3 +878,13 @@ func GetRepoLabels(e Execer, filters ...orm.Filter) ([]models.RepoLabel, error) return labels, nil } + +func GetForkCount(e Execer, sourceDID string) (int, error) { + forks := 0 + err := e.QueryRow( + `select count(source) from repos where source = ?`, sourceDID).Scan(&forks) + if err != nil { + return 0, err + } + return forks, nil +} diff --git a/appview/pages/pages.go b/appview/pages/pages.go index 88a9b373..84e637fc 100644 --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -1557,6 +1557,20 @@ func (p *Pages) RepoStars(w io.Writer, params RepoStarsParams) error { return p.executeRepo("repo/stars", w, params) } +type RepoForksParams struct { + LoggedInUser *oauth.MultiAccountUser + RepoInfo repoinfo.RepoInfo + Active string + Forks []models.Repo + Page pagination.Page + TotalCount int +} + +func (p *Pages) RepoForks(w io.Writer, params RepoForksParams) error { + params.Active = "overview" + return p.executeRepo("repo/forks", w, params) +} + type PipelinesParams struct { LoggedInUser *oauth.MultiAccountUser RepoInfo repoinfo.RepoInfo diff --git a/appview/pages/templates/layouts/repobase.html b/appview/pages/templates/layouts/repobase.html index e71d0593..557df94d 100644 --- a/appview/pages/templates/layouts/repobase.html +++ b/appview/pages/templates/layouts/repobase.html @@ -117,15 +117,24 @@ "IsStarred" .RepoInfo.IsStarred "StarCount" .RepoInfo.Stats.StarCount "RepoName" .RepoInfo.Name) }} - - {{ i "git-fork" "w-4 h-4" }} - fork - {{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }} - + {{ template "repo/fragments/feedDropdown" . }} {{ end }} diff --git a/appview/pages/templates/repo/forks.html b/appview/pages/templates/repo/forks.html new file mode 100644 index 00000000..5286db78 --- /dev/null +++ b/appview/pages/templates/repo/forks.html @@ -0,0 +1,35 @@ +{{ define "title" }}forks ยท {{ .RepoInfo.FullName }}{{ end }} + {{ define "repoContent" }} +
+

Forked by

+
+ {{ range .Forks }} + {{ $handle := resolve .Did }} + {{ $name := .Name}} +
+
+ {{ template "user/fragments/picLink" (list .Did "size-10") }} +
+ {{ $handle }} + {{ $name }} +

+ forked {{ .Created | relTimeFmt }} +

+
+
+
+ {{ end }} + {{ if eq .TotalCount 0 }} +

No forks yet.

+ {{ end }} +
+ {{ if gt .TotalCount .Page.Limit }} + {{ template "fragments/pagination" (dict + "Page" .Page + "TotalCount" .TotalCount + "BasePath" (printf "/%s/forks" .RepoInfo.FullName) + "QueryParams" (queryParams) + ) }} + {{ end }} +
+{{ end }} diff --git a/appview/repo/repo.go b/appview/repo/repo.go index 54151320..c05b5b56 100644 --- a/appview/repo/repo.go +++ b/appview/repo/repo.go @@ -1501,6 +1501,39 @@ func (rp *Repo) Stars(w http.ResponseWriter, r *http.Request) { }) } +func (rp *Repo) Forks(w http.ResponseWriter, r *http.Request) { + l := rp.logger.With("handler", "Forks") + + user := rp.oauth.GetMultiAccountUser(r) + f, err := rp.repoResolver.Resolve(r) + if err != nil { + l.Error("failed to resolve source repo", "err", err) + return + } + + page := pagination.FromContext(r.Context()) + + forks, err := db.GetReposPaginated(rp.db, page, orm.FilterEq("source", f.RepoDid)) + if err != nil { + l.Error("failed to fetch forks", "err", err, "repoAt", f.RepoAt()) + return + } + + totalCount, err := db.GetForkCount(rp.db, f.RepoDid) + if err != nil { + l.Error("failed to fetch fork count", "err", err, "repoAt", f.RepoAt()) + return + } + + rp.pages.RepoForks(w, pages.RepoForksParams{ + LoggedInUser: user, + RepoInfo: rp.repoResolver.GetRepoInfo(r, user), + Forks: forks, + Page: page, + TotalCount: totalCount, + }) +} + // this is used to rollback changes made to the PDS // // it is a no-op if the provided ATURI is empty diff --git a/appview/repo/router.go b/appview/repo/router.go index 0fe2f653..82e229a1 100644 --- a/appview/repo/router.go +++ b/appview/repo/router.go @@ -48,6 +48,7 @@ func (rp *Repo) Router(mw *middleware.Middleware) http.Handler { r.Get("/archive/{ref}", rp.DownloadArchive) r.With(middleware.Paginate).Get("/stars", rp.Stars) + r.With(middleware.Paginate).Get("/forks", rp.Forks) r.Route("/fork", func(r chi.Router) { r.Use(middleware.AuthMiddleware(rp.oauth)) -- 2.51.2