// 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/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 } // homeCols are the sortable columns of the home list, in order. var homeCols = []struct{ key, label, class string }{ {"name", "name", "c-name"}, {"desc", "description", "c-desc"}, {"push", "last push", "c-when"}, {"branch", "branch", "c-ref"}, } // 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=