Skip to content

Commit 10cdcb9

Browse files
authored
Add "Reviewed by you" filter for pull requests (#22927)
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 843f811 commit 10cdcb9

File tree

9 files changed

+100
-7
lines changed

9 files changed

+100
-7
lines changed

Diff for: models/issues/issue.go

+61
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,7 @@ type IssuesOptions struct { //nolint
11481148
PosterID int64
11491149
MentionedID int64
11501150
ReviewRequestedID int64
1151+
ReviewedID int64
11511152
SubscriberID int64
11521153
MilestoneIDs []int64
11531154
ProjectID int64
@@ -1262,6 +1263,10 @@ func (opts *IssuesOptions) setupSessionNoLimit(sess *xorm.Session) {
12621263
applyReviewRequestedCondition(sess, opts.ReviewRequestedID)
12631264
}
12641265

1266+
if opts.ReviewedID > 0 {
1267+
applyReviewedCondition(sess, opts.ReviewedID)
1268+
}
1269+
12651270
if opts.SubscriberID > 0 {
12661271
applySubscribedCondition(sess, opts.SubscriberID)
12671272
}
@@ -1432,6 +1437,36 @@ func applyReviewRequestedCondition(sess *xorm.Session, reviewRequestedID int64)
14321437
reviewRequestedID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest, reviewRequestedID)
14331438
}
14341439

1440+
func applyReviewedCondition(sess *xorm.Session, reviewedID int64) *xorm.Session {
1441+
// Query for pull requests where you are a reviewer or commenter, excluding
1442+
// any pull requests already returned by the the review requested filter.
1443+
notPoster := builder.Neq{"issue.poster_id": reviewedID}
1444+
reviewed := builder.In("issue.id", builder.
1445+
Select("issue_id").
1446+
From("review").
1447+
Where(builder.And(
1448+
builder.Neq{"type": ReviewTypeRequest},
1449+
builder.Or(
1450+
builder.Eq{"reviewer_id": reviewedID},
1451+
builder.In("reviewer_team_id", builder.
1452+
Select("team_id").
1453+
From("team_user").
1454+
Where(builder.Eq{"uid": reviewedID}),
1455+
),
1456+
),
1457+
)),
1458+
)
1459+
commented := builder.In("issue.id", builder.
1460+
Select("issue_id").
1461+
From("comment").
1462+
Where(builder.And(
1463+
builder.Eq{"poster_id": reviewedID},
1464+
builder.In("type", CommentTypeComment, CommentTypeCode, CommentTypeReview),
1465+
)),
1466+
)
1467+
return sess.And(notPoster, builder.Or(reviewed, commented))
1468+
}
1469+
14351470
func applySubscribedCondition(sess *xorm.Session, subscriberID int64) *xorm.Session {
14361471
return sess.And(
14371472
builder.
@@ -1586,6 +1621,7 @@ type IssueStats struct {
15861621
CreateCount int64
15871622
MentionCount int64
15881623
ReviewRequestedCount int64
1624+
ReviewedCount int64
15891625
}
15901626

15911627
// Filter modes.
@@ -1595,6 +1631,7 @@ const (
15951631
FilterModeCreate
15961632
FilterModeMention
15971633
FilterModeReviewRequested
1634+
FilterModeReviewed
15981635
FilterModeYourRepositories
15991636
)
16001637

@@ -1608,6 +1645,7 @@ type IssueStatsOptions struct {
16081645
MentionedID int64
16091646
PosterID int64
16101647
ReviewRequestedID int64
1648+
ReviewedID int64
16111649
IsPull util.OptionalBool
16121650
IssueIDs []int64
16131651
}
@@ -1646,6 +1684,7 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
16461684
accum.CreateCount += stats.CreateCount
16471685
accum.OpenCount += stats.MentionCount
16481686
accum.ReviewRequestedCount += stats.ReviewRequestedCount
1687+
accum.ReviewedCount += stats.ReviewedCount
16491688
i = chunk
16501689
}
16511690
return accum, nil
@@ -1703,6 +1742,10 @@ func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats,
17031742
applyReviewRequestedCondition(sess, opts.ReviewRequestedID)
17041743
}
17051744

1745+
if opts.ReviewedID > 0 {
1746+
applyReviewedCondition(sess, opts.ReviewedID)
1747+
}
1748+
17061749
switch opts.IsPull {
17071750
case util.OptionalBoolTrue:
17081751
sess.And("issue.is_pull=?", true)
@@ -1843,6 +1886,19 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
18431886
if err != nil {
18441887
return nil, err
18451888
}
1889+
case FilterModeReviewed:
1890+
stats.OpenCount, err = applyReviewedCondition(sess(cond), opts.UserID).
1891+
And("issue.is_closed = ?", false).
1892+
Count(new(Issue))
1893+
if err != nil {
1894+
return nil, err
1895+
}
1896+
stats.ClosedCount, err = applyReviewedCondition(sess(cond), opts.UserID).
1897+
And("issue.is_closed = ?", true).
1898+
Count(new(Issue))
1899+
if err != nil {
1900+
return nil, err
1901+
}
18461902
}
18471903

18481904
cond = cond.And(builder.Eq{"issue.is_closed": opts.IsClosed})
@@ -1871,6 +1927,11 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
18711927
return nil, err
18721928
}
18731929

1930+
stats.ReviewedCount, err = applyReviewedCondition(sess(cond), opts.UserID).Count(new(Issue))
1931+
if err != nil {
1932+
return nil, err
1933+
}
1934+
18741935
return stats, nil
18751936
}
18761937

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

+1
Original file line numberDiff line numberDiff line change
@@ -1323,6 +1323,7 @@ issues.filter_type.assigned_to_you = Assigned to you
13231323
issues.filter_type.created_by_you = Created by you
13241324
issues.filter_type.mentioning_you = Mentioning you
13251325
issues.filter_type.review_requested = Review requested
1326+
issues.filter_type.reviewed_by_you = Reviewed by you
13261327
issues.filter_sort = Sort
13271328
issues.filter_sort.latest = Newest
13281329
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),
@@ -2425,6 +2430,9 @@ func SearchIssues(ctx *context.Context) {
24252430
if ctx.FormBool("review_requested") {
24262431
issuesOpt.ReviewRequestedID = ctxUserID
24272432
}
2433+
if ctx.FormBool("reviewed") {
2434+
issuesOpt.ReviewedID = ctxUserID
2435+
}
24282436

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

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

+4
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,8 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
385385
filterMode = issues_model.FilterModeMention
386386
case "review_requested":
387387
filterMode = issues_model.FilterModeReviewRequested
388+
case "reviewed_by":
389+
filterMode = issues_model.FilterModeReviewed
388390
case "your_repositories":
389391
fallthrough
390392
default:
@@ -453,6 +455,8 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
453455
opts.MentionedID = ctx.Doer.ID
454456
case issues_model.FilterModeReviewRequested:
455457
opts.ReviewRequestedID = ctx.Doer.ID
458+
case issues_model.FilterModeReviewed:
459+
opts.ReviewedID = ctx.Doer.ID
456460
}
457461

458462
// 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
@@ -171,10 +171,11 @@
171171
<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>
172172
<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>
173173
<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>
174-
<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>
175174
{{if .PageIsPullList}}
176175
<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>
176+
<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>
177177
{{end}}
178+
<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>
178179
</div>
179180
</div>
180181
{{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)