Skip to content

Commit 0d10b62

Browse files
committed
Add the ability to use multiple labels as filters (go-gitea#3430)
1 parent d09704e commit 0d10b62

File tree

5 files changed

+64
-4
lines changed

5 files changed

+64
-4
lines changed

models/issue.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,10 +1140,20 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) error {
11401140
if err != nil {
11411141
return err
11421142
}
1143-
if len(labelIDs) > 0 {
1143+
if len(labelIDs) == 1 {
11441144
sess.
11451145
Join("INNER", "issue_label", "issue.id = issue_label.issue_id").
11461146
In("issue_label.label_id", labelIDs)
1147+
} else if len(labelIDs) > 1{
1148+
cond, args, _ := builder.ToSQL(builder.In("issue_label.label_id", labelIDs))
1149+
sess.
1150+
Where(fmt.Sprintf(`issue.id IN (
1151+
SELECT issue_label.issue_id
1152+
FROM issue_label
1153+
WHERE %s
1154+
GROUP BY issue_label.issue_id
1155+
HAVING COUNT(issue_label.label_id) = %d
1156+
)`, cond, len(labelIDs)), args...)
11471157
}
11481158
}
11491159
return nil
@@ -1322,9 +1332,19 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
13221332
labelIDs, err := base.StringsToInt64s(strings.Split(opts.Labels, ","))
13231333
if err != nil {
13241334
log.Warn("Malformed Labels argument: %s", opts.Labels)
1325-
} else if len(labelIDs) > 0 {
1335+
} else if len(labelIDs) == 1 {
13261336
sess.Join("INNER", "issue_label", "issue.id = issue_label.issue_id").
13271337
In("issue_label.label_id", labelIDs)
1338+
} else if len(labelIDs) > 1 {
1339+
cond, args, _ := builder.ToSQL(builder.In("issue_label.label_id", labelIDs))
1340+
sess.
1341+
Where(fmt.Sprintf(`issue.id IN (
1342+
SELECT issue_label.issue_id
1343+
FROM issue_label
1344+
WHERE %s
1345+
GROUP BY issue_label.issue_id
1346+
HAVING COUNT(issue_label.label_id) = %d
1347+
)`, cond, len(labelIDs)), args...)
13281348
}
13291349
}
13301350

models/issue_label.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ type Label struct {
6060
NumClosedIssues int
6161
NumOpenIssues int `xorm:"-"`
6262
IsChecked bool `xorm:"-"`
63+
QueryString string
64+
IsSelected bool
6365
}
6466

6567
// APIFormat converts a Label to the api.Label format
@@ -76,6 +78,25 @@ func (label *Label) CalOpenIssues() {
7678
label.NumOpenIssues = label.NumIssues - label.NumClosedIssues
7779
}
7880

81+
// CalQueryString calculates query string in issue/pulls list
82+
func (label *Label) CalQueryString(query []string) {
83+
var labelQuerySlice []string
84+
labelSelected := false
85+
labelID := fmt.Sprint(label.ID)
86+
for _, s := range query {
87+
if s == labelID {
88+
labelSelected = true
89+
} else {
90+
labelQuerySlice = append(labelQuerySlice, s)
91+
}
92+
}
93+
if !labelSelected {
94+
labelQuerySlice = append(labelQuerySlice, labelID)
95+
}
96+
label.IsSelected = labelSelected
97+
label.QueryString = strings.Join(labelQuerySlice, ",")
98+
}
99+
79100
// ForegroundColor calculates the text color for labels based
80101
// on their background color.
81102
func (label *Label) ForegroundColor() template.CSS {

routers/repo/issue_label.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
package repo
66

77
import (
8+
"strings"
9+
810
"code.gitea.io/gitea/models"
911
"code.gitea.io/gitea/modules/auth"
1012
"code.gitea.io/gitea/modules/base"
@@ -69,6 +71,23 @@ func RetrieveLabels(ctx *context.Context) {
6971
ctx.Data["SortType"] = ctx.Query("sort")
7072
}
7173

74+
// RetreveLabelsAndCalQueryString calculate query string when filtering issues/pulls
75+
func RetreveLabelsAndCalQueryString(ctx *context.Context) {
76+
labels, err := models.GetLabelsByRepoID(ctx.Repo.Repository.ID, ctx.Query("sort"))
77+
if err != nil {
78+
ctx.ServerError("RetreveLabelsAndCalQueryString.GetLabels", err)
79+
return
80+
}
81+
selectLabelsSlice := strings.Split(ctx.Query("labels"), ",")
82+
for _, l := range labels {
83+
l.CalOpenIssues()
84+
l.CalQueryString(selectLabelsSlice)
85+
}
86+
ctx.Data["Labels"] = labels
87+
ctx.Data["NumLabels"] = len(labels)
88+
ctx.Data["SortType"] = ctx.Query("sort")
89+
}
90+
7291
// NewLabel create new label for repository
7392
func NewLabel(ctx *context.Context, form auth.CreateLabelForm) {
7493
ctx.Data["Title"] = ctx.Tr("repo.labels")

routers/routes/routes.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ func RegisterRoutes(m *macaron.Macaron) {
585585

586586
m.Group("/:username/:reponame", func() {
587587
m.Group("", func() {
588-
m.Get("/^:type(issues|pulls)$", repo.RetrieveLabels, repo.Issues)
588+
m.Get("/^:type(issues|pulls)$", repo.RetreveLabelsAndCalQueryString, repo.Issues)
589589
m.Get("/^:type(issues|pulls)$/:index", repo.ViewIssue)
590590
m.Get("/labels/", context.CheckAnyUnit(models.UnitTypeIssues, models.UnitTypePullRequests), repo.RetrieveLabels, repo.Labels)
591591
m.Get("/milestones", context.CheckAnyUnit(models.UnitTypeIssues, models.UnitTypePullRequests), repo.Milestones)

templates/repo/issue/list.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
<div class="menu">
4343
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_label_no_select"}}</a>
4444
{{range .Labels}}
45-
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.ID}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}"><span class="octicon {{if eq $.SelectLabels .ID}}octicon-check{{end}}"></span><span class="label color" style="background-color: {{.Color}}"></span> {{.Name}}</a>
45+
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.QueryString}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}"><span class="octicon {{if .IsSelected}}octicon-check{{end}}"></span><span class="label color" style="background-color: {{.Color}}"></span> {{.Name}}</a>
4646
{{end}}
4747
</div>
4848
</div>

0 commit comments

Comments
 (0)