]> source.dussan.org Git - gitea.git/commitdiff
Add review requested filter on pull request overview (#13701)
authorJimmy Praet <jimmy.praet@telenet.be>
Sun, 17 Jan 2021 16:34:19 +0000 (17:34 +0100)
committerGitHub <noreply@github.com>
Sun, 17 Jan 2021 16:34:19 +0000 (17:34 +0100)
* Add review requested filter on pull request overview #13682

fix formatting

* add review_requested filter to /repos/issues/search API endpoint

* only Approve and Reject status should supersede Request status

* add support for team reviews

* refactor: remove duplication of issue filtering conditions

models/issue.go
options/locale/locale_en-US.ini
routers/api/v1/repo/issue.go
routers/repo/issue.go
routers/user/home.go
templates/repo/issue/list.tmpl
templates/repo/issue/milestone_issues.tmpl
templates/swagger/v1_json.tmpl
templates/user/dashboard/issues.tmpl

index 7731a59ed0f4d4132c7d231af9a2a1163331abc1..3cd85dc6afcd86a6154fc154ca87c41218fbb3b5 100644 (file)
@@ -1090,6 +1090,7 @@ type IssuesOptions struct {
        AssigneeID         int64
        PosterID           int64
        MentionedID        int64
+       ReviewRequestedID  int64
        MilestoneIDs       []int64
        ProjectID          int64
        ProjectBoardID     int64
@@ -1151,8 +1152,7 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
        }
 
        if len(opts.RepoIDs) > 0 {
-               // In case repository IDs are provided but actually no repository has issue.
-               sess.In("issue.repo_id", opts.RepoIDs)
+               applyReposCondition(sess, opts.RepoIDs)
        }
 
        switch opts.IsClosed {
@@ -1163,18 +1163,19 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
        }
 
        if opts.AssigneeID > 0 {
-               sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
-                       And("issue_assignees.assignee_id = ?", opts.AssigneeID)
+               applyAssigneeCondition(sess, opts.AssigneeID)
        }
 
        if opts.PosterID > 0 {
-               sess.And("issue.poster_id=?", opts.PosterID)
+               applyPosterCondition(sess, opts.PosterID)
        }
 
        if opts.MentionedID > 0 {
-               sess.Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
-                       And("issue_user.is_mentioned = ?", true).
-                       And("issue_user.uid = ?", opts.MentionedID)
+               applyMentionedCondition(sess, opts.MentionedID)
+       }
+
+       if opts.ReviewRequestedID > 0 {
+               applyReviewRequestedCondition(sess, opts.ReviewRequestedID)
        }
 
        if len(opts.MilestoneIDs) > 0 {
@@ -1232,6 +1233,33 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
        }
 }
 
+func applyReposCondition(sess *xorm.Session, repoIDs []int64) *xorm.Session {
+       return sess.In("issue.repo_id", repoIDs)
+}
+
+func applyAssigneeCondition(sess *xorm.Session, assigneeID int64) *xorm.Session {
+       return sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
+               And("issue_assignees.assignee_id = ?", assigneeID)
+}
+
+func applyPosterCondition(sess *xorm.Session, posterID int64) *xorm.Session {
+       return sess.And("issue.poster_id=?", posterID)
+}
+
+func applyMentionedCondition(sess *xorm.Session, mentionedID int64) *xorm.Session {
+       return sess.Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
+               And("issue_user.is_mentioned = ?", true).
+               And("issue_user.uid = ?", mentionedID)
+}
+
+func applyReviewRequestedCondition(sess *xorm.Session, reviewRequestedID int64) *xorm.Session {
+       return sess.Join("INNER", []string{"review", "r"}, "issue.id = r.issue_id").
+               And("r.type = ?", ReviewTypeRequest).
+               And("r.reviewer_id = ? and r.id in (select max(id) from review where issue_id = r.issue_id and reviewer_id = r.reviewer_id and type in (?, ?, ?))"+
+                       " or r.reviewer_team_id in (select team_id from team_user where uid = ?)",
+                       reviewRequestedID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest, reviewRequestedID)
+}
+
 // CountIssuesByRepo map from repoID to number of issues matching the options
 func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) {
        sess := x.NewSession()
@@ -1364,6 +1392,7 @@ type IssueStats struct {
        AssignCount            int64
        CreateCount            int64
        MentionCount           int64
+       ReviewRequestedCount   int64
 }
 
 // Filter modes.
@@ -1372,6 +1401,7 @@ const (
        FilterModeAssign
        FilterModeCreate
        FilterModeMention
+       FilterModeReviewRequested
 )
 
 func parseCountResult(results []map[string][]byte) int64 {
@@ -1387,14 +1417,15 @@ func parseCountResult(results []map[string][]byte) int64 {
 
 // IssueStatsOptions contains parameters accepted by GetIssueStats.
 type IssueStatsOptions struct {
-       RepoID      int64
-       Labels      string
-       MilestoneID int64
-       AssigneeID  int64
-       MentionedID int64
-       PosterID    int64
-       IsPull      util.OptionalBool
-       IssueIDs    []int64
+       RepoID            int64
+       Labels            string
+       MilestoneID       int64
+       AssigneeID        int64
+       MentionedID       int64
+       PosterID          int64
+       ReviewRequestedID int64
+       IsPull            util.OptionalBool
+       IssueIDs          []int64
 }
 
 // GetIssueStats returns issue statistic information by given conditions.
@@ -1423,6 +1454,7 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
                accum.AssignCount += stats.AssignCount
                accum.CreateCount += stats.CreateCount
                accum.OpenCount += stats.MentionCount
+               accum.ReviewRequestedCount += stats.ReviewRequestedCount
                i = chunk
        }
        return accum, nil
@@ -1460,18 +1492,19 @@ func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats,
                }
 
                if opts.AssigneeID > 0 {
-                       sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
-                               And("issue_assignees.assignee_id = ?", opts.AssigneeID)
+                       applyAssigneeCondition(sess, opts.AssigneeID)
                }
 
                if opts.PosterID > 0 {
-                       sess.And("issue.poster_id = ?", opts.PosterID)
+                       applyPosterCondition(sess, opts.PosterID)
                }
 
                if opts.MentionedID > 0 {
-                       sess.Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
-                               And("issue_user.uid = ?", opts.MentionedID).
-                               And("issue_user.is_mentioned = ?", true)
+                       applyMentionedCondition(sess, opts.MentionedID)
+               }
+
+               if opts.ReviewRequestedID > 0 {
+                       applyReviewRequestedCondition(sess, opts.ReviewRequestedID)
                }
 
                switch opts.IsPull {
@@ -1539,57 +1572,66 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
 
        switch opts.FilterMode {
        case FilterModeAll:
-               stats.OpenCount, err = sess(cond).And("issue.is_closed = ?", false).
-                       And(builder.In("issue.repo_id", opts.UserRepoIDs)).
+               stats.OpenCount, err = applyReposCondition(sess(cond), opts.UserRepoIDs).
+                       And("issue.is_closed = ?", false).
                        Count(new(Issue))
                if err != nil {
                        return nil, err
                }
-               stats.ClosedCount, err = sess(cond).And("issue.is_closed = ?", true).
-                       And(builder.In("issue.repo_id", opts.UserRepoIDs)).
+               stats.ClosedCount, err = applyReposCondition(sess(cond), opts.UserRepoIDs).
+                       And("issue.is_closed = ?", true).
                        Count(new(Issue))
                if err != nil {
                        return nil, err
                }
        case FilterModeAssign:
-               stats.OpenCount, err = sess(cond).And("issue.is_closed = ?", false).
-                       Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
-                       And("issue_assignees.assignee_id = ?", opts.UserID).
+               stats.OpenCount, err = applyAssigneeCondition(sess(cond), opts.UserID).
+                       And("issue.is_closed = ?", false).
                        Count(new(Issue))
                if err != nil {
                        return nil, err
                }
-               stats.ClosedCount, err = sess(cond).And("issue.is_closed = ?", true).
-                       Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
-                       And("issue_assignees.assignee_id = ?", opts.UserID).
+               stats.ClosedCount, err = applyAssigneeCondition(sess(cond), opts.UserID).
+                       And("issue.is_closed = ?", true).
                        Count(new(Issue))
                if err != nil {
                        return nil, err
                }
        case FilterModeCreate:
-               stats.OpenCount, err = sess(cond).And("issue.is_closed = ?", false).
-                       And("issue.poster_id = ?", opts.UserID).
+               stats.OpenCount, err = applyPosterCondition(sess(cond), opts.UserID).
+                       And("issue.is_closed = ?", false).
                        Count(new(Issue))
                if err != nil {
                        return nil, err
                }
-               stats.ClosedCount, err = sess(cond).And("issue.is_closed = ?", true).
-                       And("issue.poster_id = ?", opts.UserID).
+               stats.ClosedCount, err = applyPosterCondition(sess(cond), opts.UserID).
+                       And("issue.is_closed = ?", true).
                        Count(new(Issue))
                if err != nil {
                        return nil, err
                }
        case FilterModeMention:
-               stats.OpenCount, err = sess(cond).And("issue.is_closed = ?", false).
-                       Join("INNER", "issue_user", "issue.id = issue_user.issue_id and issue_user.is_mentioned = ?", true).
-                       And("issue_user.uid = ?", opts.UserID).
+               stats.OpenCount, err = applyMentionedCondition(sess(cond), opts.UserID).
+                       And("issue.is_closed = ?", false).
                        Count(new(Issue))
                if err != nil {
                        return nil, err
                }
-               stats.ClosedCount, err = sess(cond).And("issue.is_closed = ?", true).
-                       Join("INNER", "issue_user", "issue.id = issue_user.issue_id and issue_user.is_mentioned = ?", true).
-                       And("issue_user.uid = ?", opts.UserID).
+               stats.ClosedCount, err = applyMentionedCondition(sess(cond), opts.UserID).
+                       And("issue.is_closed = ?", true).
+                       Count(new(Issue))
+               if err != nil {
+                       return nil, err
+               }
+       case FilterModeReviewRequested:
+               stats.OpenCount, err = applyReviewRequestedCondition(sess(cond), opts.UserID).
+                       And("issue.is_closed = ?", false).
+                       Count(new(Issue))
+               if err != nil {
+                       return nil, err
+               }
+               stats.ClosedCount, err = applyReviewRequestedCondition(sess(cond), opts.UserID).
+                       And("issue.is_closed = ?", true).
                        Count(new(Issue))
                if err != nil {
                        return nil, err
@@ -1597,32 +1639,27 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
        }
 
        cond = cond.And(builder.Eq{"issue.is_closed": opts.IsClosed})
-       stats.AssignCount, err = sess(cond).
-               Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
-               And("issue_assignees.assignee_id = ?", opts.UserID).
-               Count(new(Issue))
+       stats.AssignCount, err = applyAssigneeCondition(sess(cond), opts.UserID).Count(new(Issue))
        if err != nil {
                return nil, err
        }
 
-       stats.CreateCount, err = sess(cond).
-               And("poster_id = ?", opts.UserID).
-               Count(new(Issue))
+       stats.CreateCount, err = applyPosterCondition(sess(cond), opts.UserID).Count(new(Issue))
        if err != nil {
                return nil, err
        }
 
-       stats.MentionCount, err = sess(cond).
-               Join("INNER", "issue_user", "issue.id = issue_user.issue_id and issue_user.is_mentioned = ?", true).
-               And("issue_user.uid = ?", opts.UserID).
-               Count(new(Issue))
+       stats.MentionCount, err = applyMentionedCondition(sess(cond), opts.UserID).Count(new(Issue))
        if err != nil {
                return nil, err
        }
 
-       stats.YourRepositoriesCount, err = sess(cond).
-               And(builder.In("issue.repo_id", opts.UserRepoIDs)).
-               Count(new(Issue))
+       stats.YourRepositoriesCount, err = applyReposCondition(sess(cond), opts.UserRepoIDs).Count(new(Issue))
+       if err != nil {
+               return nil, err
+       }
+
+       stats.ReviewRequestedCount, err = applyReviewRequestedCondition(sess(cond), opts.UserID).Count(new(Issue))
        if err != nil {
                return nil, err
        }
@@ -1646,13 +1683,11 @@ func GetRepoIssueStats(repoID, uid int64, filterMode int, isPull bool) (numOpen
 
        switch filterMode {
        case FilterModeAssign:
-               openCountSession.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
-                       And("issue_assignees.assignee_id = ?", uid)
-               closedCountSession.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
-                       And("issue_assignees.assignee_id = ?", uid)
+               applyAssigneeCondition(openCountSession, uid)
+               applyAssigneeCondition(closedCountSession, uid)
        case FilterModeCreate:
-               openCountSession.And("poster_id = ?", uid)
-               closedCountSession.And("poster_id = ?", uid)
+               applyPosterCondition(openCountSession, uid)
+               applyPosterCondition(closedCountSession, uid)
        }
 
        openResult, _ := openCountSession.Count(new(Issue))
index 4546a06e8180394ecc132d53e2516322cd6760a3..73451eeebb136813a0ad3b080f8ece87e0a593f5 100644 (file)
@@ -1030,6 +1030,7 @@ issues.filter_type.all_issues = All issues
 issues.filter_type.assigned_to_you = Assigned to you
 issues.filter_type.created_by_you = Created by you
 issues.filter_type.mentioning_you = Mentioning you
+issues.filter_type.review_requested = Review requested
 issues.filter_sort = Sort
 issues.filter_sort.latest = Newest
 issues.filter_sort.oldest = Oldest
index 25153ad50773c4ef323855cd9e9826efc80c8ea9..bab8f373ce271f7f19a0993031d148ec565fc074 100644 (file)
@@ -79,6 +79,10 @@ func SearchIssues(ctx *context.APIContext) {
        //   in: query
        //   description: filter (issues / pulls) mentioning you, default is false
        //   type: boolean
+       // - name: review_requested
+       //   in: query
+       //   description: filter pulls requesting your review, default is false
+       //   type: boolean
        // - name: page
        //   in: query
        //   description: page number of results to return (1-based)
@@ -204,7 +208,7 @@ func SearchIssues(ctx *context.APIContext) {
                        UpdatedAfterUnix:   since,
                }
 
-               // Filter for: Created by User, Assigned to User, Mentioning User
+               // Filter for: Created by User, Assigned to User, Mentioning User, Review of User Requested
                if ctx.QueryBool("created") {
                        issuesOpt.PosterID = ctx.User.ID
                }
@@ -214,6 +218,9 @@ func SearchIssues(ctx *context.APIContext) {
                if ctx.QueryBool("mentioned") {
                        issuesOpt.MentionedID = ctx.User.ID
                }
+               if ctx.QueryBool("review_requested") {
+                       issuesOpt.ReviewRequestedID = ctx.User.ID
+               }
 
                if issues, err = models.Issues(issuesOpt); err != nil {
                        ctx.Error(http.StatusInternalServerError, "Issues", err)
index 478baf8d86aa86b9a2faa8a0ebec06e87ebc144b..7b4044ac7b81b9faaa7bb05b1b05ce5120d068b2 100644 (file)
@@ -113,16 +113,17 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
        var err error
        viewType := ctx.Query("type")
        sortType := ctx.Query("sort")
-       types := []string{"all", "your_repositories", "assigned", "created_by", "mentioned"}
+       types := []string{"all", "your_repositories", "assigned", "created_by", "mentioned", "review_requested"}
        if !util.IsStringInSlice(viewType, types, true) {
                viewType = "all"
        }
 
        var (
-               assigneeID  = ctx.QueryInt64("assignee")
-               posterID    int64
-               mentionedID int64
-               forceEmpty  bool
+               assigneeID        = ctx.QueryInt64("assignee")
+               posterID          int64
+               mentionedID       int64
+               reviewRequestedID int64
+               forceEmpty        bool
        )
 
        if ctx.IsSigned {
@@ -133,6 +134,8 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
                        mentionedID = ctx.User.ID
                case "assigned":
                        assigneeID = ctx.User.ID
+               case "review_requested":
+                       reviewRequestedID = ctx.User.ID
                }
        }
 
@@ -169,14 +172,15 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
                issueStats = &models.IssueStats{}
        } else {
                issueStats, err = models.GetIssueStats(&models.IssueStatsOptions{
-                       RepoID:      repo.ID,
-                       Labels:      selectLabels,
-                       MilestoneID: milestoneID,
-                       AssigneeID:  assigneeID,
-                       MentionedID: mentionedID,
-                       PosterID:    posterID,
-                       IsPull:      isPullOption,
-                       IssueIDs:    issueIDs,
+                       RepoID:            repo.ID,
+                       Labels:            selectLabels,
+                       MilestoneID:       milestoneID,
+                       AssigneeID:        assigneeID,
+                       MentionedID:       mentionedID,
+                       PosterID:          posterID,
+                       ReviewRequestedID: reviewRequestedID,
+                       IsPull:            isPullOption,
+                       IssueIDs:          issueIDs,
                })
                if err != nil {
                        ctx.ServerError("GetIssueStats", err)
@@ -217,17 +221,18 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
                                Page:     pager.Paginater.Current(),
                                PageSize: setting.UI.IssuePagingNum,
                        },
-                       RepoIDs:      []int64{repo.ID},
-                       AssigneeID:   assigneeID,
-                       PosterID:     posterID,
-                       MentionedID:  mentionedID,
-                       MilestoneIDs: mileIDs,
-                       ProjectID:    projectID,
-                       IsClosed:     util.OptionalBoolOf(isShowClosed),
-                       IsPull:       isPullOption,
-                       LabelIDs:     labelIDs,
-                       SortType:     sortType,
-                       IssueIDs:     issueIDs,
+                       RepoIDs:           []int64{repo.ID},
+                       AssigneeID:        assigneeID,
+                       PosterID:          posterID,
+                       MentionedID:       mentionedID,
+                       ReviewRequestedID: reviewRequestedID,
+                       MilestoneIDs:      mileIDs,
+                       ProjectID:         projectID,
+                       IsClosed:          util.OptionalBoolOf(isShowClosed),
+                       IsPull:            isPullOption,
+                       LabelIDs:          labelIDs,
+                       SortType:          sortType,
+                       IssueIDs:          issueIDs,
                })
                if err != nil {
                        ctx.ServerError("Issues", err)
index 3c27bbe2a8dcd52befb4e767297dd36ebfa25462..a8a8a5f3d750377dcbf00813bc10b358c6bb7bf2 100644 (file)
@@ -392,6 +392,8 @@ func buildIssueOverview(ctx *context.Context, unitType models.UnitType) {
                filterMode = models.FilterModeCreate
        case "mentioned":
                filterMode = models.FilterModeMention
+       case "review_requested":
+               filterMode = models.FilterModeReviewRequested
        case "your_repositories": // filterMode already set to All
        default:
                viewType = "your_repositories"
@@ -431,7 +433,9 @@ func buildIssueOverview(ctx *context.Context, unitType models.UnitType) {
        case models.FilterModeCreate:
                opts.PosterID = ctx.User.ID
        case models.FilterModeMention:
-               opts.MentionedID = ctx.User.ID
+               opts.MentionedID = ctxUser.ID
+       case models.FilterModeReviewRequested:
+               opts.ReviewRequestedID = ctxUser.ID
        }
 
        if ctxUser.IsOrganization() {
index 2b64d267006288af39bb076a1fc00ecabbbd5c6e..7b856e60cb6cbbb26bfe83c5746f542f719414b1 100644 (file)
@@ -89,6 +89,9 @@
                                                                <a class="{{if eq .ViewType "assigned"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=assigned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.assigned_to_you"}}</a>
                                                                <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}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.created_by_you"}}</a>
                                                                <a class="{{if eq .ViewType "mentioned"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=mentioned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.mentioning_you"}}</a>
+                                                               {{if .PageIsPullList}}
+                                                                       <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}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.review_requested"}}</a>
+                                                               {{end}}
                                                        </div>
                                                </div>
                                        {{end}}
index 638134c442620ee01fe9840d623094aac58b5345..c2c81682ff0ff4ed3d4e75a883c00fa5165d8925 100644 (file)
@@ -88,6 +88,7 @@
                                                                <a class="{{if eq .ViewType "assigned"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=assigned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.assigned_to_you"}}</a>
                                                                <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}}">{{.i18n.Tr "repo.issues.filter_type.created_by_you"}}</a>
                                                                <a class="{{if eq .ViewType "mentioned"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=mentioned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.mentioning_you"}}</a>
+                                                               <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}}">{{.i18n.Tr "repo.issues.filter_type.review_requested"}}</a>
                                                        </div>
                                                </div>
                                        {{end}}
index 81ccf4f7253462beb612400ad68d52bd8eb94470..6650c09bb44b74438e590bba3e7ad69487bc480f 100644 (file)
             "name": "mentioned",
             "in": "query"
           },
+          {
+            "type": "boolean",
+            "description": "filter pulls requesting your review, default is false",
+            "name": "review_requested",
+            "in": "query"
+          },
           {
             "type": "integer",
             "description": "page number of results to return (1-based)",
index 62428dce423023efbcd83307357c851e995425ac..dfd0e5d8ec32a668e6115535bc9adf94e3f5832f 100644 (file)
                                                {{.i18n.Tr "repo.issues.filter_type.mentioning_you"}}
                                                <strong class="ui right">{{CountFmt .IssueStats.MentionCount}}</strong>
                                        </a>
+                                       {{if .PageIsPulls}}
+                                               <a class="{{if eq .ViewType "review_requested"}}ui basic blue button{{end}} item" href="{{.Link}}?type=review_requested&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state={{.State}}">
+                                                       {{.i18n.Tr "repo.issues.filter_type.review_requested"}}
+                                                       <strong class="ui right">{{CountFmt .IssueStats.ReviewRequestedCount}}</strong>
+                                               </a>
+                                       {{end}}          
                                        <div class="ui divider"></div>
                                        <a class="{{if not $.RepoIDs}}ui basic blue button{{end}} repo name item" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&q={{$.Keyword}}">
                                                <span class="text truncate">All</span>