mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-29 07:03:55 +03:00
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
159
models/issue.go
159
models/issue.go
|
@ -1090,6 +1090,7 @@ type IssuesOptions struct {
|
||||||
AssigneeID int64
|
AssigneeID int64
|
||||||
PosterID int64
|
PosterID int64
|
||||||
MentionedID int64
|
MentionedID int64
|
||||||
|
ReviewRequestedID int64
|
||||||
MilestoneIDs []int64
|
MilestoneIDs []int64
|
||||||
ProjectID int64
|
ProjectID int64
|
||||||
ProjectBoardID int64
|
ProjectBoardID int64
|
||||||
|
@ -1151,8 +1152,7 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(opts.RepoIDs) > 0 {
|
if len(opts.RepoIDs) > 0 {
|
||||||
// In case repository IDs are provided but actually no repository has issue.
|
applyReposCondition(sess, opts.RepoIDs)
|
||||||
sess.In("issue.repo_id", opts.RepoIDs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch opts.IsClosed {
|
switch opts.IsClosed {
|
||||||
|
@ -1163,18 +1163,19 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.AssigneeID > 0 {
|
if opts.AssigneeID > 0 {
|
||||||
sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
|
applyAssigneeCondition(sess, opts.AssigneeID)
|
||||||
And("issue_assignees.assignee_id = ?", opts.AssigneeID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.PosterID > 0 {
|
if opts.PosterID > 0 {
|
||||||
sess.And("issue.poster_id=?", opts.PosterID)
|
applyPosterCondition(sess, opts.PosterID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.MentionedID > 0 {
|
if opts.MentionedID > 0 {
|
||||||
sess.Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
|
applyMentionedCondition(sess, opts.MentionedID)
|
||||||
And("issue_user.is_mentioned = ?", true).
|
}
|
||||||
And("issue_user.uid = ?", opts.MentionedID)
|
|
||||||
|
if opts.ReviewRequestedID > 0 {
|
||||||
|
applyReviewRequestedCondition(sess, opts.ReviewRequestedID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(opts.MilestoneIDs) > 0 {
|
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
|
// CountIssuesByRepo map from repoID to number of issues matching the options
|
||||||
func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) {
|
func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) {
|
||||||
sess := x.NewSession()
|
sess := x.NewSession()
|
||||||
|
@ -1364,6 +1392,7 @@ type IssueStats struct {
|
||||||
AssignCount int64
|
AssignCount int64
|
||||||
CreateCount int64
|
CreateCount int64
|
||||||
MentionCount int64
|
MentionCount int64
|
||||||
|
ReviewRequestedCount int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter modes.
|
// Filter modes.
|
||||||
|
@ -1372,6 +1401,7 @@ const (
|
||||||
FilterModeAssign
|
FilterModeAssign
|
||||||
FilterModeCreate
|
FilterModeCreate
|
||||||
FilterModeMention
|
FilterModeMention
|
||||||
|
FilterModeReviewRequested
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseCountResult(results []map[string][]byte) int64 {
|
func parseCountResult(results []map[string][]byte) int64 {
|
||||||
|
@ -1387,14 +1417,15 @@ func parseCountResult(results []map[string][]byte) int64 {
|
||||||
|
|
||||||
// IssueStatsOptions contains parameters accepted by GetIssueStats.
|
// IssueStatsOptions contains parameters accepted by GetIssueStats.
|
||||||
type IssueStatsOptions struct {
|
type IssueStatsOptions struct {
|
||||||
RepoID int64
|
RepoID int64
|
||||||
Labels string
|
Labels string
|
||||||
MilestoneID int64
|
MilestoneID int64
|
||||||
AssigneeID int64
|
AssigneeID int64
|
||||||
MentionedID int64
|
MentionedID int64
|
||||||
PosterID int64
|
PosterID int64
|
||||||
IsPull util.OptionalBool
|
ReviewRequestedID int64
|
||||||
IssueIDs []int64
|
IsPull util.OptionalBool
|
||||||
|
IssueIDs []int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIssueStats returns issue statistic information by given conditions.
|
// GetIssueStats returns issue statistic information by given conditions.
|
||||||
|
@ -1423,6 +1454,7 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
|
||||||
accum.AssignCount += stats.AssignCount
|
accum.AssignCount += stats.AssignCount
|
||||||
accum.CreateCount += stats.CreateCount
|
accum.CreateCount += stats.CreateCount
|
||||||
accum.OpenCount += stats.MentionCount
|
accum.OpenCount += stats.MentionCount
|
||||||
|
accum.ReviewRequestedCount += stats.ReviewRequestedCount
|
||||||
i = chunk
|
i = chunk
|
||||||
}
|
}
|
||||||
return accum, nil
|
return accum, nil
|
||||||
|
@ -1460,18 +1492,19 @@ func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats,
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.AssigneeID > 0 {
|
if opts.AssigneeID > 0 {
|
||||||
sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
|
applyAssigneeCondition(sess, opts.AssigneeID)
|
||||||
And("issue_assignees.assignee_id = ?", opts.AssigneeID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.PosterID > 0 {
|
if opts.PosterID > 0 {
|
||||||
sess.And("issue.poster_id = ?", opts.PosterID)
|
applyPosterCondition(sess, opts.PosterID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.MentionedID > 0 {
|
if opts.MentionedID > 0 {
|
||||||
sess.Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
|
applyMentionedCondition(sess, opts.MentionedID)
|
||||||
And("issue_user.uid = ?", opts.MentionedID).
|
}
|
||||||
And("issue_user.is_mentioned = ?", true)
|
|
||||||
|
if opts.ReviewRequestedID > 0 {
|
||||||
|
applyReviewRequestedCondition(sess, opts.ReviewRequestedID)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch opts.IsPull {
|
switch opts.IsPull {
|
||||||
|
@ -1539,57 +1572,66 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
|
||||||
|
|
||||||
switch opts.FilterMode {
|
switch opts.FilterMode {
|
||||||
case FilterModeAll:
|
case FilterModeAll:
|
||||||
stats.OpenCount, err = sess(cond).And("issue.is_closed = ?", false).
|
stats.OpenCount, err = applyReposCondition(sess(cond), opts.UserRepoIDs).
|
||||||
And(builder.In("issue.repo_id", opts.UserRepoIDs)).
|
And("issue.is_closed = ?", false).
|
||||||
Count(new(Issue))
|
Count(new(Issue))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
stats.ClosedCount, err = sess(cond).And("issue.is_closed = ?", true).
|
stats.ClosedCount, err = applyReposCondition(sess(cond), opts.UserRepoIDs).
|
||||||
And(builder.In("issue.repo_id", opts.UserRepoIDs)).
|
And("issue.is_closed = ?", true).
|
||||||
Count(new(Issue))
|
Count(new(Issue))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case FilterModeAssign:
|
case FilterModeAssign:
|
||||||
stats.OpenCount, err = sess(cond).And("issue.is_closed = ?", false).
|
stats.OpenCount, err = applyAssigneeCondition(sess(cond), opts.UserID).
|
||||||
Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
|
And("issue.is_closed = ?", false).
|
||||||
And("issue_assignees.assignee_id = ?", opts.UserID).
|
|
||||||
Count(new(Issue))
|
Count(new(Issue))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
stats.ClosedCount, err = sess(cond).And("issue.is_closed = ?", true).
|
stats.ClosedCount, err = applyAssigneeCondition(sess(cond), opts.UserID).
|
||||||
Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
|
And("issue.is_closed = ?", true).
|
||||||
And("issue_assignees.assignee_id = ?", opts.UserID).
|
|
||||||
Count(new(Issue))
|
Count(new(Issue))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case FilterModeCreate:
|
case FilterModeCreate:
|
||||||
stats.OpenCount, err = sess(cond).And("issue.is_closed = ?", false).
|
stats.OpenCount, err = applyPosterCondition(sess(cond), opts.UserID).
|
||||||
And("issue.poster_id = ?", opts.UserID).
|
And("issue.is_closed = ?", false).
|
||||||
Count(new(Issue))
|
Count(new(Issue))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
stats.ClosedCount, err = sess(cond).And("issue.is_closed = ?", true).
|
stats.ClosedCount, err = applyPosterCondition(sess(cond), opts.UserID).
|
||||||
And("issue.poster_id = ?", opts.UserID).
|
And("issue.is_closed = ?", true).
|
||||||
Count(new(Issue))
|
Count(new(Issue))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case FilterModeMention:
|
case FilterModeMention:
|
||||||
stats.OpenCount, err = sess(cond).And("issue.is_closed = ?", false).
|
stats.OpenCount, err = applyMentionedCondition(sess(cond), opts.UserID).
|
||||||
Join("INNER", "issue_user", "issue.id = issue_user.issue_id and issue_user.is_mentioned = ?", true).
|
And("issue.is_closed = ?", false).
|
||||||
And("issue_user.uid = ?", opts.UserID).
|
|
||||||
Count(new(Issue))
|
Count(new(Issue))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
stats.ClosedCount, err = sess(cond).And("issue.is_closed = ?", true).
|
stats.ClosedCount, err = applyMentionedCondition(sess(cond), opts.UserID).
|
||||||
Join("INNER", "issue_user", "issue.id = issue_user.issue_id and issue_user.is_mentioned = ?", true).
|
And("issue.is_closed = ?", true).
|
||||||
And("issue_user.uid = ?", opts.UserID).
|
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))
|
Count(new(Issue))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -1597,32 +1639,27 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cond = cond.And(builder.Eq{"issue.is_closed": opts.IsClosed})
|
cond = cond.And(builder.Eq{"issue.is_closed": opts.IsClosed})
|
||||||
stats.AssignCount, err = sess(cond).
|
stats.AssignCount, err = applyAssigneeCondition(sess(cond), opts.UserID).Count(new(Issue))
|
||||||
Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
|
|
||||||
And("issue_assignees.assignee_id = ?", opts.UserID).
|
|
||||||
Count(new(Issue))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
stats.CreateCount, err = sess(cond).
|
stats.CreateCount, err = applyPosterCondition(sess(cond), opts.UserID).Count(new(Issue))
|
||||||
And("poster_id = ?", opts.UserID).
|
|
||||||
Count(new(Issue))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
stats.MentionCount, err = sess(cond).
|
stats.MentionCount, err = applyMentionedCondition(sess(cond), opts.UserID).Count(new(Issue))
|
||||||
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))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
stats.YourRepositoriesCount, err = sess(cond).
|
stats.YourRepositoriesCount, err = applyReposCondition(sess(cond), opts.UserRepoIDs).Count(new(Issue))
|
||||||
And(builder.In("issue.repo_id", opts.UserRepoIDs)).
|
if err != nil {
|
||||||
Count(new(Issue))
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
stats.ReviewRequestedCount, err = applyReviewRequestedCondition(sess(cond), opts.UserID).Count(new(Issue))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1646,13 +1683,11 @@ func GetRepoIssueStats(repoID, uid int64, filterMode int, isPull bool) (numOpen
|
||||||
|
|
||||||
switch filterMode {
|
switch filterMode {
|
||||||
case FilterModeAssign:
|
case FilterModeAssign:
|
||||||
openCountSession.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
|
applyAssigneeCondition(openCountSession, uid)
|
||||||
And("issue_assignees.assignee_id = ?", uid)
|
applyAssigneeCondition(closedCountSession, uid)
|
||||||
closedCountSession.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
|
|
||||||
And("issue_assignees.assignee_id = ?", uid)
|
|
||||||
case FilterModeCreate:
|
case FilterModeCreate:
|
||||||
openCountSession.And("poster_id = ?", uid)
|
applyPosterCondition(openCountSession, uid)
|
||||||
closedCountSession.And("poster_id = ?", uid)
|
applyPosterCondition(closedCountSession, uid)
|
||||||
}
|
}
|
||||||
|
|
||||||
openResult, _ := openCountSession.Count(new(Issue))
|
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.assigned_to_you = Assigned to you
|
||||||
issues.filter_type.created_by_you = Created by you
|
issues.filter_type.created_by_you = Created by you
|
||||||
issues.filter_type.mentioning_you = Mentioning you
|
issues.filter_type.mentioning_you = Mentioning you
|
||||||
|
issues.filter_type.review_requested = Review requested
|
||||||
issues.filter_sort = Sort
|
issues.filter_sort = Sort
|
||||||
issues.filter_sort.latest = Newest
|
issues.filter_sort.latest = Newest
|
||||||
issues.filter_sort.oldest = Oldest
|
issues.filter_sort.oldest = Oldest
|
||||||
|
|
|
@ -79,6 +79,10 @@ func SearchIssues(ctx *context.APIContext) {
|
||||||
// in: query
|
// in: query
|
||||||
// description: filter (issues / pulls) mentioning you, default is false
|
// description: filter (issues / pulls) mentioning you, default is false
|
||||||
// type: boolean
|
// type: boolean
|
||||||
|
// - name: review_requested
|
||||||
|
// in: query
|
||||||
|
// description: filter pulls requesting your review, default is false
|
||||||
|
// type: boolean
|
||||||
// - name: page
|
// - name: page
|
||||||
// in: query
|
// in: query
|
||||||
// description: page number of results to return (1-based)
|
// description: page number of results to return (1-based)
|
||||||
|
@ -204,7 +208,7 @@ func SearchIssues(ctx *context.APIContext) {
|
||||||
UpdatedAfterUnix: since,
|
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") {
|
if ctx.QueryBool("created") {
|
||||||
issuesOpt.PosterID = ctx.User.ID
|
issuesOpt.PosterID = ctx.User.ID
|
||||||
}
|
}
|
||||||
|
@ -214,6 +218,9 @@ func SearchIssues(ctx *context.APIContext) {
|
||||||
if ctx.QueryBool("mentioned") {
|
if ctx.QueryBool("mentioned") {
|
||||||
issuesOpt.MentionedID = ctx.User.ID
|
issuesOpt.MentionedID = ctx.User.ID
|
||||||
}
|
}
|
||||||
|
if ctx.QueryBool("review_requested") {
|
||||||
|
issuesOpt.ReviewRequestedID = ctx.User.ID
|
||||||
|
}
|
||||||
|
|
||||||
if issues, err = models.Issues(issuesOpt); err != nil {
|
if issues, err = models.Issues(issuesOpt); err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "Issues", err)
|
ctx.Error(http.StatusInternalServerError, "Issues", err)
|
||||||
|
|
|
@ -113,16 +113,17 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
|
||||||
var err error
|
var err error
|
||||||
viewType := ctx.Query("type")
|
viewType := ctx.Query("type")
|
||||||
sortType := ctx.Query("sort")
|
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) {
|
if !util.IsStringInSlice(viewType, types, true) {
|
||||||
viewType = "all"
|
viewType = "all"
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
assigneeID = ctx.QueryInt64("assignee")
|
assigneeID = ctx.QueryInt64("assignee")
|
||||||
posterID int64
|
posterID int64
|
||||||
mentionedID int64
|
mentionedID int64
|
||||||
forceEmpty bool
|
reviewRequestedID int64
|
||||||
|
forceEmpty bool
|
||||||
)
|
)
|
||||||
|
|
||||||
if ctx.IsSigned {
|
if ctx.IsSigned {
|
||||||
|
@ -133,6 +134,8 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
|
||||||
mentionedID = ctx.User.ID
|
mentionedID = ctx.User.ID
|
||||||
case "assigned":
|
case "assigned":
|
||||||
assigneeID = ctx.User.ID
|
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{}
|
issueStats = &models.IssueStats{}
|
||||||
} else {
|
} else {
|
||||||
issueStats, err = models.GetIssueStats(&models.IssueStatsOptions{
|
issueStats, err = models.GetIssueStats(&models.IssueStatsOptions{
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
Labels: selectLabels,
|
Labels: selectLabels,
|
||||||
MilestoneID: milestoneID,
|
MilestoneID: milestoneID,
|
||||||
AssigneeID: assigneeID,
|
AssigneeID: assigneeID,
|
||||||
MentionedID: mentionedID,
|
MentionedID: mentionedID,
|
||||||
PosterID: posterID,
|
PosterID: posterID,
|
||||||
IsPull: isPullOption,
|
ReviewRequestedID: reviewRequestedID,
|
||||||
IssueIDs: issueIDs,
|
IsPull: isPullOption,
|
||||||
|
IssueIDs: issueIDs,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetIssueStats", err)
|
ctx.ServerError("GetIssueStats", err)
|
||||||
|
@ -217,17 +221,18 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
|
||||||
Page: pager.Paginater.Current(),
|
Page: pager.Paginater.Current(),
|
||||||
PageSize: setting.UI.IssuePagingNum,
|
PageSize: setting.UI.IssuePagingNum,
|
||||||
},
|
},
|
||||||
RepoIDs: []int64{repo.ID},
|
RepoIDs: []int64{repo.ID},
|
||||||
AssigneeID: assigneeID,
|
AssigneeID: assigneeID,
|
||||||
PosterID: posterID,
|
PosterID: posterID,
|
||||||
MentionedID: mentionedID,
|
MentionedID: mentionedID,
|
||||||
MilestoneIDs: mileIDs,
|
ReviewRequestedID: reviewRequestedID,
|
||||||
ProjectID: projectID,
|
MilestoneIDs: mileIDs,
|
||||||
IsClosed: util.OptionalBoolOf(isShowClosed),
|
ProjectID: projectID,
|
||||||
IsPull: isPullOption,
|
IsClosed: util.OptionalBoolOf(isShowClosed),
|
||||||
LabelIDs: labelIDs,
|
IsPull: isPullOption,
|
||||||
SortType: sortType,
|
LabelIDs: labelIDs,
|
||||||
IssueIDs: issueIDs,
|
SortType: sortType,
|
||||||
|
IssueIDs: issueIDs,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("Issues", err)
|
ctx.ServerError("Issues", err)
|
||||||
|
|
|
@ -392,6 +392,8 @@ func buildIssueOverview(ctx *context.Context, unitType models.UnitType) {
|
||||||
filterMode = models.FilterModeCreate
|
filterMode = models.FilterModeCreate
|
||||||
case "mentioned":
|
case "mentioned":
|
||||||
filterMode = models.FilterModeMention
|
filterMode = models.FilterModeMention
|
||||||
|
case "review_requested":
|
||||||
|
filterMode = models.FilterModeReviewRequested
|
||||||
case "your_repositories": // filterMode already set to All
|
case "your_repositories": // filterMode already set to All
|
||||||
default:
|
default:
|
||||||
viewType = "your_repositories"
|
viewType = "your_repositories"
|
||||||
|
@ -431,7 +433,9 @@ func buildIssueOverview(ctx *context.Context, unitType models.UnitType) {
|
||||||
case models.FilterModeCreate:
|
case models.FilterModeCreate:
|
||||||
opts.PosterID = ctx.User.ID
|
opts.PosterID = ctx.User.ID
|
||||||
case models.FilterModeMention:
|
case models.FilterModeMention:
|
||||||
opts.MentionedID = ctx.User.ID
|
opts.MentionedID = ctxUser.ID
|
||||||
|
case models.FilterModeReviewRequested:
|
||||||
|
opts.ReviewRequestedID = ctxUser.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctxUser.IsOrganization() {
|
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 "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 "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>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{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 "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 "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 "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>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -1911,6 +1911,12 @@
|
||||||
"name": "mentioned",
|
"name": "mentioned",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "filter pulls requesting your review, default is false",
|
||||||
|
"name": "review_requested",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "page number of results to return (1-based)",
|
"description": "page number of results to return (1-based)",
|
||||||
|
|
|
@ -21,6 +21,12 @@
|
||||||
{{.i18n.Tr "repo.issues.filter_type.mentioning_you"}}
|
{{.i18n.Tr "repo.issues.filter_type.mentioning_you"}}
|
||||||
<strong class="ui right">{{CountFmt .IssueStats.MentionCount}}</strong>
|
<strong class="ui right">{{CountFmt .IssueStats.MentionCount}}</strong>
|
||||||
</a>
|
</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>
|
<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}}">
|
<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>
|
<span class="text truncate">All</span>
|
||||||
|
|
Loading…
Reference in a new issue