diff --git a/models/issues/label.go b/models/issues/label.go index 24ca9d8c1cb..815d47c0541 100644 --- a/models/issues/label.go +++ b/models/issues/label.go @@ -433,12 +433,13 @@ func GetLabelsByRepoID(ctx context.Context, repoID int64, sortType string, listO case "reversealphabetically": sess.Desc("name") case "leastissues": - sess.Asc("num_issues") + sess.OrderBy("num_issues - num_closed_issues ASC") case "mostissues": - sess.Desc("num_issues") + sess.OrderBy("num_issues - num_closed_issues DESC") default: sess.Asc("name") } + sess.Asc("id") if listOptions.Page > 0 { db.SetSessionPagination(sess, &listOptions) @@ -508,12 +509,13 @@ func GetLabelsByOrgID(ctx context.Context, orgID int64, sortType string, listOpt case "reversealphabetically": sess.Desc("name") case "leastissues": - sess.Asc("num_issues") + sess.OrderBy("num_issues - num_closed_issues ASC") case "mostissues": - sess.Desc("num_issues") + sess.OrderBy("num_issues - num_closed_issues DESC") default: sess.Asc("name") } + sess.Asc("id") if listOptions.Page > 0 { db.SetSessionPagination(sess, &listOptions) diff --git a/models/issues/label_test.go b/models/issues/label_test.go index 94958e414fc..b4f58f3a41f 100644 --- a/models/issues/label_test.go +++ b/models/issues/label_test.go @@ -191,6 +191,8 @@ func TestGetLabelsInRepoByIDs(t *testing.T) { func TestGetLabelsByRepoID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) + _, err := db.GetEngine(t.Context()).ID(2).Cols("num_issues", "num_closed_issues").Update(&issues_model.Label{NumIssues: 3, NumClosedIssues: 3}) + assert.NoError(t, err) testSuccess := func(repoID int64, sortType string, expectedIssueIDs []int64) { labels, err := issues_model.GetLabelsByRepoID(t.Context(), repoID, sortType, db.ListOptions{}) assert.NoError(t, err) @@ -258,6 +260,8 @@ func TestGetLabelsInOrgByIDs(t *testing.T) { func TestGetLabelsByOrgID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) + _, err := db.GetEngine(t.Context()).ID(3).Cols("num_issues", "num_closed_issues").Update(&issues_model.Label{NumIssues: 3, NumClosedIssues: 3}) + assert.NoError(t, err) testSuccess := func(orgID int64, sortType string, expectedIssueIDs []int64) { labels, err := issues_model.GetLabelsByOrgID(t.Context(), orgID, sortType, db.ListOptions{}) assert.NoError(t, err) @@ -271,7 +275,7 @@ func TestGetLabelsByOrgID(t *testing.T) { testSuccess(3, "reversealphabetically", []int64{4, 3}) testSuccess(3, "default", []int64{3, 4}) - _, err := issues_model.GetLabelsByOrgID(t.Context(), 0, "leastissues", db.ListOptions{}) + _, err = issues_model.GetLabelsByOrgID(t.Context(), 0, "leastissues", db.ListOptions{}) assert.True(t, issues_model.IsErrOrgLabelNotExist(err)) _, err = issues_model.GetLabelsByOrgID(t.Context(), -1, "leastissues", db.ListOptions{}) diff --git a/routers/web/repo/issue_label.go b/routers/web/repo/issue_label.go index 5004b9d9783..4cdff3c37cb 100644 --- a/routers/web/repo/issue_label.go +++ b/routers/web/repo/issue_label.go @@ -4,8 +4,10 @@ package repo import ( + "cmp" "errors" "net/http" + "slices" "gitea.dev/models/db" issues_model "gitea.dev/models/issues" @@ -77,6 +79,16 @@ func RetrieveLabelsForList(ctx *context.Context) { for _, l := range orgLabels { l.CalOpenOrgIssues(ctx, ctx.Repo.Repository.ID, l.ID) } + switch ctx.FormString("sort") { + case "leastissues": + slices.SortStableFunc(orgLabels, func(label1, label2 *issues_model.Label) int { + return cmp.Compare(label1.NumOpenRepoIssues, label2.NumOpenRepoIssues) + }) + case "mostissues": + slices.SortStableFunc(orgLabels, func(label1, label2 *issues_model.Label) int { + return cmp.Compare(label2.NumOpenRepoIssues, label1.NumOpenRepoIssues) + }) + } ctx.Data["OrgLabels"] = orgLabels org, err := organization.GetOrgByName(ctx, ctx.Repo.Owner.LowerName) diff --git a/routers/web/repo/issue_label_test.go b/routers/web/repo/issue_label_test.go index 7e141b0a65a..19451a9ab95 100644 --- a/routers/web/repo/issue_label_test.go +++ b/routers/web/repo/issue_label_test.go @@ -9,6 +9,7 @@ import ( "strings" "testing" + "gitea.dev/models/db" issues_model "gitea.dev/models/issues" "gitea.dev/models/unittest" "gitea.dev/modules/base" @@ -51,14 +52,23 @@ func testInitializeLabels(t *testing.T) { } func testRetrieveLabels(t *testing.T) { + issueLabel := &issues_model.IssueLabel{IssueID: 6, LabelID: 3} + assert.NoError(t, db.Insert(t.Context(), issueLabel)) + defer func() { + _, err := db.DeleteByBean(t.Context(), issueLabel) + assert.NoError(t, err) + }() + for _, testCase := range []struct { - RepoID int64 - Sort string - ExpectedLabelIDs []int64 + RepoID int64 + Sort string + ExpectedLabelIDs []int64 + ExpectedOrgLabelIDs []int64 }{ - {1, "", []int64{1, 2}}, - {1, "leastissues", []int64{2, 1}}, - {2, "", []int64{}}, + {1, "", []int64{1, 2}, nil}, + {1, "leastissues", []int64{2, 1}, nil}, + {2, "", nil, nil}, + {3, "mostissues", []int64{10}, []int64{3, 4}}, } { ctx, _ := contexttest.MockContext(t, "user/repo/issues") contexttest.LoadUser(t, ctx, 2) @@ -66,13 +76,15 @@ func testRetrieveLabels(t *testing.T) { ctx.Req.Form.Set("sort", testCase.Sort) RetrieveLabelsForList(ctx) assert.False(t, ctx.Written()) - labels, ok := ctx.Data["Labels"].([]*issues_model.Label) - assert.True(t, ok) - if assert.Len(t, labels, len(testCase.ExpectedLabelIDs)) { - for i, label := range labels { - assert.Equal(t, testCase.ExpectedLabelIDs[i], label.ID) + labelIDs := func(key string) (ids []int64) { + labels, _ := ctx.Data[key].([]*issues_model.Label) + for _, label := range labels { + ids = append(ids, label.ID) } + return ids } + assert.Equal(t, testCase.ExpectedLabelIDs, labelIDs("Labels")) + assert.Equal(t, testCase.ExpectedOrgLabelIDs, labelIDs("OrgLabels")) } }