Skip to content

Commit a7e905b

Browse files
committed
Add "Reviewed by you" filter for pull requests
This includes pull requests that you approved, requested changes or commented on. Currently such pull requests are not visible in any of the filters on /pulls, while they may need further action like merging, or prodding the author or reviewers. Especially when working with a large team on a repository it's helpful to get a full overview of pull requests that may need your attention, without having to sift through the complete list.
1 parent 007d181 commit a7e905b

File tree

11 files changed

+115
-7
lines changed

11 files changed

+115
-7
lines changed

Diff for: models/issues/issue.go

+58
Original file line numberDiff line numberDiff line change
@@ -1119,6 +1119,7 @@ type IssuesOptions struct { //nolint
11191119
PosterID int64
11201120
MentionedID int64
11211121
ReviewRequestedID int64
1122+
ReviewedID int64
11221123
SubscriberID int64
11231124
MilestoneIDs []int64
11241125
ProjectID int64
@@ -1233,6 +1234,10 @@ func (opts *IssuesOptions) setupSessionNoLimit(sess *xorm.Session) {
12331234
applyReviewRequestedCondition(sess, opts.ReviewRequestedID)
12341235
}
12351236

1237+
if opts.ReviewedID > 0 {
1238+
applyReviewedCondition(sess, opts.ReviewedID)
1239+
}
1240+
12361241
if opts.SubscriberID > 0 {
12371242
applySubscribedCondition(sess, opts.SubscriberID)
12381243
}
@@ -1403,6 +1408,33 @@ func applyReviewRequestedCondition(sess *xorm.Session, reviewRequestedID int64)
14031408
reviewRequestedID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest, reviewRequestedID)
14041409
}
14051410

1411+
func applyReviewedCondition(sess *xorm.Session, reviewedID int64) *xorm.Session {
1412+
// Query for pull requests where you are a reviewer or commenter, excluding
1413+
// any pull requests already returned by the the review requested filter.
1414+
notPoster := builder.Neq{"issue.poster_id": reviewedID}
1415+
reviewed := builder.In("issue.id", builder.
1416+
Select("issue_id").
1417+
From("review").
1418+
Where(builder.And(
1419+
builder.Neq{"type": ReviewTypeRequest},
1420+
builder.Or(
1421+
builder.Eq{"reviewer_id": reviewedID},
1422+
builder.In("reviewer_team_id", builder.
1423+
Select("team_id").
1424+
From("team_user").
1425+
Where(builder.Eq{"uid": reviewedID}),
1426+
),
1427+
),
1428+
)),
1429+
)
1430+
comment := builder.In("issue.id", builder.
1431+
Select("issue_id").
1432+
From("comment").
1433+
Where(builder.Eq{"poster_id": reviewedID}),
1434+
)
1435+
return sess.And(notPoster, reviewed, comment)
1436+
}
1437+
14061438
func applySubscribedCondition(sess *xorm.Session, subscriberID int64) *xorm.Session {
14071439
return sess.And(
14081440
builder.
@@ -1557,6 +1589,7 @@ type IssueStats struct {
15571589
CreateCount int64
15581590
MentionCount int64
15591591
ReviewRequestedCount int64
1592+
ReviewedCount int64
15601593
}
15611594

15621595
// Filter modes.
@@ -1566,6 +1599,7 @@ const (
15661599
FilterModeCreate
15671600
FilterModeMention
15681601
FilterModeReviewRequested
1602+
FilterModeReviewed
15691603
FilterModeYourRepositories
15701604
)
15711605

@@ -1579,6 +1613,7 @@ type IssueStatsOptions struct {
15791613
MentionedID int64
15801614
PosterID int64
15811615
ReviewRequestedID int64
1616+
ReviewedID int64
15821617
IsPull util.OptionalBool
15831618
IssueIDs []int64
15841619
}
@@ -1617,6 +1652,7 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
16171652
accum.CreateCount += stats.CreateCount
16181653
accum.OpenCount += stats.MentionCount
16191654
accum.ReviewRequestedCount += stats.ReviewRequestedCount
1655+
accum.ReviewedCount += stats.ReviewedCount
16201656
i = chunk
16211657
}
16221658
return accum, nil
@@ -1674,6 +1710,10 @@ func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats,
16741710
applyReviewRequestedCondition(sess, opts.ReviewRequestedID)
16751711
}
16761712

1713+
if opts.ReviewedID > 0 {
1714+
applyReviewedCondition(sess, opts.ReviewedID)
1715+
}
1716+
16771717
switch opts.IsPull {
16781718
case util.OptionalBoolTrue:
16791719
sess.And("issue.is_pull=?", true)
@@ -1814,6 +1854,19 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
18141854
if err != nil {
18151855
return nil, err
18161856
}
1857+
case FilterModeReviewed:
1858+
stats.OpenCount, err = applyReviewedCondition(sess(cond), opts.UserID).
1859+
And("issue.is_closed = ?", false).
1860+
Count(new(Issue))
1861+
if err != nil {
1862+
return nil, err
1863+
}
1864+
stats.ClosedCount, err = applyReviewedCondition(sess(cond), opts.UserID).
1865+
And("issue.is_closed = ?", true).
1866+
Count(new(Issue))
1867+
if err != nil {
1868+
return nil, err
1869+
}
18171870
}
18181871

18191872
cond = cond.And(builder.Eq{"issue.is_closed": opts.IsClosed})
@@ -1842,6 +1895,11 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
18421895
return nil, err
18431896
}
18441897

1898+
stats.ReviewedCount, err = applyReviewedCondition(sess(cond), opts.UserID).Count(new(Issue))
1899+
if err != nil {
1900+
return nil, err
1901+
}
1902+
18451903
return stats, nil
18461904
}
18471905

Diff for: models/migrations/migrations.go

+2
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,8 @@ var migrations = []Migration{
459459
NewMigration("Add card_type column to project table", v1_19.AddCardTypeToProjectTable),
460460
// v242 -> v243
461461
NewMigration("Alter gpg_key_import content TEXT field to MEDIUMTEXT", v1_19.AlterPublicGPGKeyImportContentFieldToMediumText),
462+
// v243 -> v244
463+
NewMigration("Add exclusive label", v1_19.AddExclusiveLabel),
462464
}
463465

464466
// GetCurrentDBVersion returns the current db version

Diff for: models/migrations/v1_19/v244.go

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package v1_19 //nolint
5+
6+
import (
7+
"xorm.io/xorm"
8+
)
9+
10+
func AddExclusiveLabel(x *xorm.Engine) error {
11+
type Label struct {
12+
Exclusive bool
13+
}
14+
15+
return x.Sync(new(Label))
16+
}

Diff for: options/locale/locale_en-US.ini

+1
Original file line numberDiff line numberDiff line change
@@ -1322,6 +1322,7 @@ issues.filter_type.assigned_to_you = Assigned to you
13221322
issues.filter_type.created_by_you = Created by you
13231323
issues.filter_type.mentioning_you = Mentioning you
13241324
issues.filter_type.review_requested = Review requested
1325+
issues.filter_type.reviewed_by_you = Reviewed by you
13251326
issues.filter_sort = Sort
13261327
issues.filter_sort.latest = Newest
13271328
issues.filter_sort.oldest = Oldest

Diff for: routers/api/v1/repo/issue.go

+7
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ func SearchIssues(ctx *context.APIContext) {
9292
// in: query
9393
// description: filter pulls requesting your review, default is false
9494
// type: boolean
95+
// - name: reviewed
96+
// in: query
97+
// description: filter pulls reviewed by you, default is false
98+
// type: boolean
9599
// - name: owner
96100
// in: query
97101
// description: filter by owner
@@ -266,6 +270,9 @@ func SearchIssues(ctx *context.APIContext) {
266270
if ctx.FormBool("review_requested") {
267271
issuesOpt.ReviewRequestedID = ctxUserID
268272
}
273+
if ctx.FormBool("reviewed") {
274+
issuesOpt.ReviewedID = ctxUserID
275+
}
269276

270277
if issues, err = issues_model.Issues(ctx, issuesOpt); err != nil {
271278
ctx.Error(http.StatusInternalServerError, "Issues", err)

Diff for: routers/web/repo/issue.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
138138
var err error
139139
viewType := ctx.FormString("type")
140140
sortType := ctx.FormString("sort")
141-
types := []string{"all", "your_repositories", "assigned", "created_by", "mentioned", "review_requested"}
141+
types := []string{"all", "your_repositories", "assigned", "created_by", "mentioned", "review_requested", "reviewed_by"}
142142
if !util.SliceContainsString(types, viewType, true) {
143143
viewType = "all"
144144
}
@@ -148,6 +148,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
148148
posterID = ctx.FormInt64("poster")
149149
mentionedID int64
150150
reviewRequestedID int64
151+
reviewedID int64
151152
forceEmpty bool
152153
)
153154

@@ -161,6 +162,8 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
161162
assigneeID = ctx.Doer.ID
162163
case "review_requested":
163164
reviewRequestedID = ctx.Doer.ID
165+
case "reviewed_by":
166+
reviewedID = ctx.Doer.ID
164167
}
165168
}
166169

@@ -208,6 +211,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
208211
MentionedID: mentionedID,
209212
PosterID: posterID,
210213
ReviewRequestedID: reviewRequestedID,
214+
ReviewedID: reviewedID,
211215
IsPull: isPullOption,
212216
IssueIDs: issueIDs,
213217
})
@@ -255,6 +259,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
255259
PosterID: posterID,
256260
MentionedID: mentionedID,
257261
ReviewRequestedID: reviewRequestedID,
262+
ReviewedID: reviewedID,
258263
MilestoneIDs: mileIDs,
259264
ProjectID: projectID,
260265
IsClosed: util.OptionalBoolOf(isShowClosed),
@@ -2409,6 +2414,9 @@ func SearchIssues(ctx *context.Context) {
24092414
if ctx.FormBool("review_requested") {
24102415
issuesOpt.ReviewRequestedID = ctxUserID
24112416
}
2417+
if ctx.FormBool("reviewed") {
2418+
issuesOpt.ReviewedID = ctxUserID
2419+
}
24122420

24132421
if issues, err = issues_model.Issues(ctx, issuesOpt); err != nil {
24142422
ctx.Error(http.StatusInternalServerError, "Issues", err.Error())

Diff for: routers/web/user/home.go

+4
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,8 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
366366
filterMode = issues_model.FilterModeMention
367367
case "review_requested":
368368
filterMode = issues_model.FilterModeReviewRequested
369+
case "reviewed_by":
370+
filterMode = issues_model.FilterModeReviewed
369371
case "your_repositories":
370372
fallthrough
371373
default:
@@ -434,6 +436,8 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
434436
opts.MentionedID = ctx.Doer.ID
435437
case issues_model.FilterModeReviewRequested:
436438
opts.ReviewRequestedID = ctx.Doer.ID
439+
case issues_model.FilterModeReviewed:
440+
opts.ReviewedID = ctx.Doer.ID
437441
}
438442

439443
// keyword holds the search term entered into the search field.

Diff for: templates/repo/issue/list.tmpl

+2-1
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,11 @@
165165
<a class="{{if eq .ViewType "all"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=all&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.all_issues"}}</a>
166166
<a class="{{if eq .ViewType "assigned"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=assigned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.assigned_to_you"}}</a>
167167
<a class="{{if eq .ViewType "created_by"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=created_by&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.created_by_you"}}</a>
168-
<a class="{{if eq .ViewType "mentioned"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=mentioned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.mentioning_you"}}</a>
169168
{{if .PageIsPullList}}
170169
<a class="{{if eq .ViewType "review_requested"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=review_requested&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.review_requested"}}</a>
170+
<a class="{{if eq .ViewType "reviewed_by"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=reviewed_by&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.reviewed_by_you"}}</a>
171171
{{end}}
172+
<a class="{{if eq .ViewType "mentioned"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=mentioned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.mentioning_you"}}</a>
172173
</div>
173174
</div>
174175
{{end}}

Diff for: templates/repo/issue/milestone_issues.tmpl

+2-1
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,9 @@
111111
<a class="{{if eq .ViewType "all"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=all&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.all_issues"}}</a>
112112
<a class="{{if eq .ViewType "assigned"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=assigned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.assigned_to_you"}}</a>
113113
<a class="{{if eq .ViewType "created_by"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=created_by&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.created_by_you"}}</a>
114-
<a class="{{if eq .ViewType "mentioned"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=mentioned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.mentioning_you"}}</a>
115114
<a class="{{if eq .ViewType "review_requested"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=review_requested&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.review_requested"}}</a>
115+
<a class="{{if eq .ViewType "reviewed_by"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=reviewed_by&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.reviewed_by_you"}}</a>
116+
<a class="{{if eq .ViewType "mentioned"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=mentioned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.mentioning_you"}}</a>
116117
</div>
117118
</div>
118119
{{end}}

Diff for: templates/swagger/v1_json.tmpl

+6
Original file line numberDiff line numberDiff line change
@@ -2366,6 +2366,12 @@
23662366
"name": "review_requested",
23672367
"in": "query"
23682368
},
2369+
{
2370+
"type": "boolean",
2371+
"description": "filter pulls reviewed by you, default is false",
2372+
"name": "reviewed",
2373+
"in": "query"
2374+
},
23692375
{
23702376
"type": "string",
23712377
"description": "filter by owner",

Diff for: templates/user/dashboard/issues.tmpl

+8-4
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,20 @@
1717
{{.locale.Tr "repo.issues.filter_type.created_by_you"}}
1818
<strong class="ui right">{{CountFmt .IssueStats.CreateCount}}</strong>
1919
</a>
20-
<a class="{{if eq .ViewType "mentioned"}}ui basic primary button{{end}} item" href="{{.Link}}?type=mentioned&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state={{.State}}">
21-
{{.locale.Tr "repo.issues.filter_type.mentioning_you"}}
22-
<strong class="ui right">{{CountFmt .IssueStats.MentionCount}}</strong>
23-
</a>
2420
{{if .PageIsPulls}}
2521
<a class="{{if eq .ViewType "review_requested"}}ui basic primary button{{end}} item" href="{{.Link}}?type=review_requested&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state={{.State}}">
2622
{{.locale.Tr "repo.issues.filter_type.review_requested"}}
2723
<strong class="ui right">{{CountFmt .IssueStats.ReviewRequestedCount}}</strong>
2824
</a>
25+
<a class="{{if eq .ViewType "reviewed_by"}}ui basic primary button{{end}} item" href="{{.Link}}?type=reviewed_by&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state={{.State}}">
26+
{{.locale.Tr "repo.issues.filter_type.reviewed_by_you"}}
27+
<strong class="ui right">{{CountFmt .IssueStats.ReviewedCount}}</strong>
28+
</a>
2929
{{end}}
30+
<a class="{{if eq .ViewType "mentioned"}}ui basic primary button{{end}} item" href="{{.Link}}?type=mentioned&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state={{.State}}">
31+
{{.locale.Tr "repo.issues.filter_type.mentioning_you"}}
32+
<strong class="ui right">{{CountFmt .IssueStats.MentionCount}}</strong>
33+
</a>
3034
<div class="ui divider"></div>
3135
<a class="{{if not $.RepoIDs}}ui basic primary button{{end}} repo name item" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&q={{$.Keyword}}">
3236
<span class="text truncate">All</span>

0 commit comments

Comments
 (0)