From 7eebf5642cffe30b2eaea811165d6eccfb10bfab Mon Sep 17 00:00:00 2001 From: Antonin Delpeuch Date: Thu, 14 May 2026 22:30:56 +0200 Subject: [PATCH] fix: paginate list of repositories in a team (#12549) Follow-up to #12103 / !12447, which added pagination for lists of team members. @mahlzahn has [noticed](https://codeberg.org/forgejo/forgejo/issues/12103#issuecomment-14454947) that the same problem applies to the list of repositories controlled by a team, so this PR adds pagination for that too. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/12549 Reviewed-by: Robert Wolff --- models/organization/team.go | 10 ++++++++-- routers/web/org/teams.go | 10 +++++++++- templates/org/team/repositories.tmpl | 1 + tests/integration/org_team_test.go | 26 ++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/models/organization/team.go b/models/organization/team.go index b7b93821ad..abc60fcb72 100644 --- a/models/organization/team.go +++ b/models/organization/team.go @@ -150,13 +150,19 @@ func (t *Team) IsMember(ctx context.Context, userID int64) bool { return isMember } -// LoadRepositories returns paginated repositories in team of organization. +// LoadRepositories returns the repositories of the team in t.Repos. func (t *Team) LoadRepositories(ctx context.Context) (err error) { + return t.LoadPaginatedRepositories(ctx, db.ListOptionsAll) +} + +// LoadPaginatedRepositories loads paginated repositories of the team in t.Repos. +func (t *Team) LoadPaginatedRepositories(ctx context.Context, listOptions db.ListOptions) (err error) { if t.Repos != nil { return nil } t.Repos, err = GetTeamRepositories(ctx, &SearchTeamRepoOptions{ - TeamID: t.ID, + ListOptions: listOptions, + TeamID: t.ID, }) return err } diff --git a/routers/web/org/teams.go b/routers/web/org/teams.go index 1b76a6abf9..a4cc647cdb 100644 --- a/routers/web/org/teams.go +++ b/routers/web/org/teams.go @@ -413,10 +413,18 @@ func TeamRepositories(ctx *context.Context) { return } - if err := ctx.Org.Team.LoadRepositories(ctx); err != nil { + page := max(ctx.FormInt("page"), 1) + total := ctx.Org.Team.NumRepos + pager := context.NewPagination(total, setting.UI.User.RepoPagingNum, page, 5) + opts := db.ListOptions{} + opts.Page = page + opts.PageSize = setting.UI.User.RepoPagingNum + + if err := ctx.Org.Team.LoadPaginatedRepositories(ctx, opts); err != nil { ctx.ServerError("GetRepositories", err) return } + ctx.Data["Page"] = pager ctx.Data["Units"] = unit_model.Units ctx.HTML(http.StatusOK, tplTeamRepositories) } diff --git a/templates/org/team/repositories.tmpl b/templates/org/team/repositories.tmpl index 782e8ca004..015afde571 100644 --- a/templates/org/team/repositories.tmpl +++ b/templates/org/team/repositories.tmpl @@ -50,6 +50,7 @@ {{end}} + {{template "base/paginate" .}} diff --git a/tests/integration/org_team_test.go b/tests/integration/org_team_test.go index 2ed3025785..e4bdfb801a 100644 --- a/tests/integration/org_team_test.go +++ b/tests/integration/org_team_test.go @@ -46,3 +46,29 @@ func TestPaginatedMembers(t *testing.T) { doc := NewHTMLParser(t, newVar) assert.Contains(t, strings.TrimSpace(doc.Find("a.item.navigation:contains('Next')").AttrOr("href", "")), fmt.Sprintf("%s?page=2", teamURL)) } + +func TestPaginatedRepos(t *testing.T) { + defer tests.PrepareTestEnv(t)() + // To make sure that pagination kicks in even though the test team has few repos + defer test.MockVariableValue(&setting.UI.User.RepoPagingNum, 2)() + + org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + + assert.GreaterOrEqual(t, team.NumRepos, 3) + isOrgMember, err := organization.IsOrganizationMember(db.DefaultContext, org.ID, user.ID) + require.NoError(t, err) + assert.True(t, isOrgMember) + isTeamMember, err := organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, user.ID) + require.NoError(t, err) + assert.True(t, isTeamMember) + assert.Equal(t, org.ID, team.OrgID) + + session := loginUser(t, user.Name) + + teamURL := fmt.Sprintf("/org/%s/teams/%s/repositories", org.Name, team.LowerName) + body := session.MakeRequest(t, NewRequest(t, "GET", teamURL), http.StatusOK).Body + doc := NewHTMLParser(t, body) + assert.Contains(t, strings.TrimSpace(doc.Find("a.item.navigation:contains('Next')").AttrOr("href", "")), fmt.Sprintf("%s?page=2", teamURL)) +}