Add review requested filter on pull request overview (#13701)
* 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
This commit is contained in:
		
							parent
							
								
									872d308892
								
							
						
					
					
						commit
						acb1ceb1f4
					
				
					 9 changed files with 156 additions and 88 deletions
				
			
		
							
								
								
									
										143
									
								
								models/issue.go
									
									
									
									
									
								
							
							
						
						
									
										143
									
								
								models/issue.go
									
									
									
									
									
								
							|  | @ -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 { | ||||
|  | @ -1393,6 +1423,7 @@ type IssueStatsOptions struct { | |||
| 	AssigneeID        int64 | ||||
| 	MentionedID       int64 | ||||
| 	PosterID          int64 | ||||
| 	ReviewRequestedID int64 | ||||
| 	IsPull            util.OptionalBool | ||||
| 	IssueIDs          []int64 | ||||
| } | ||||
|  | @ -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)) | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -113,7 +113,7 @@ 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" | ||||
| 	} | ||||
|  | @ -122,6 +122,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti | |||
| 		assigneeID        = ctx.QueryInt64("assignee") | ||||
| 		posterID          int64 | ||||
| 		mentionedID       int64 | ||||
| 		reviewRequestedID int64 | ||||
| 		forceEmpty        bool | ||||
| 	) | ||||
| 
 | ||||
|  | @ -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 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -175,6 +178,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti | |||
| 			AssigneeID:        assigneeID, | ||||
| 			MentionedID:       mentionedID, | ||||
| 			PosterID:          posterID, | ||||
| 			ReviewRequestedID: reviewRequestedID, | ||||
| 			IsPull:            isPullOption, | ||||
| 			IssueIDs:          issueIDs, | ||||
| 		}) | ||||
|  | @ -221,6 +225,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti | |||
| 			AssigneeID:        assigneeID, | ||||
| 			PosterID:          posterID, | ||||
| 			MentionedID:       mentionedID, | ||||
| 			ReviewRequestedID: reviewRequestedID, | ||||
| 			MilestoneIDs:      mileIDs, | ||||
| 			ProjectID:         projectID, | ||||
| 			IsClosed:          util.OptionalBoolOf(isShowClosed), | ||||
|  |  | |||
|  | @ -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() { | ||||
|  |  | |||
|  | @ -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}} | ||||
|  |  | |||
|  | @ -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}} | ||||
|  |  | |||
|  | @ -1911,6 +1911,12 @@ | |||
|             "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)", | ||||
|  |  | |||
|  | @ -21,6 +21,12 @@ | |||
| 						{{.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> | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue