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") }}
+
+
+
+ {{ 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))