// SPDX-License-Identifier: AGPL-3.0-or-later package web import ( "context" "net/http" "sort" "strings" "time" "github.com/a-h/templ" "bnema.dev/ermite/internal/domain" "bnema.dev/ermite/internal/ports" ) // maxRepos bounds the repositories one page lists. const maxRepos = 1000 // pageSize is the page size asked from the commit lists: the largest the use // case accepts for them. const pageSize = 100 // listRepos reads the repositories the visitor may see, ordered by name. // Every page of ListRepos scans the whole repository list and reads the HEAD // of each repository of the page, so the list is asked in one page of up to // maxRepos: one scan in the common case, whatever the cap of the use case is // (a lower one only means more pages, followed by their token). func (s *Server) listRepos(ctx context.Context) ([]ports.RepoView, error) { var repos []ports.RepoView token := "" for len(repos) < maxRepos { page, err := s.cfg.Repos.ListPage(ctx, principal(ctx), maxRepos, token) if err != nil { return nil, err } for _, repo := range page.Repos { view, err := s.cfg.Repos.View(ctx, repo) if err != nil { return nil, err } repos = append(repos, view) } if token = page.NextPageToken; token == "" { break } } return repos, nil } // homeSorts are the orders the home list offers, in order. The query also // accepts "desc" and "branch", which the page does not link to. var homeSorts = []struct{ key, label string }{ {"push", "last push"}, {"name", "name"}, } // homeKeys are the keys of ?sort= that sortRepos knows. var homeKeys = []string{"push", "name", "desc", "branch"} // sortRepos orders repos by the column key; ties keep the order by name. func sortRepos(repos []ports.RepoView, key string, desc bool) { less := func(a, b ports.RepoView) bool { switch key { case "desc": return strings.ToLower(a.Description) < strings.ToLower(b.Description) case "branch": return a.DefaultBranch < b.DefaultBranch case "push": return a.PushedAt.Before(b.PushedAt) } return a.Name.String() < b.Name.String() } sort.SliceStable(repos, func(i, j int) bool { if desc { return less(repos[j], repos[i]) } return less(repos[i], repos[j]) }) } // home lists the repositories: /?sort=