diff --git a/models/issues/issue.go b/models/issues/issue.go index dc9e5c5acd18..50c9b7711997 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -1572,6 +1572,7 @@ type IssueStatsOptions struct { RepoID int64 Labels string MilestoneID int64 + ProjectID int64 AssigneeID int64 MentionedID int64 PosterID int64 @@ -1650,6 +1651,11 @@ func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats, sess.And("issue.milestone_id = ?", opts.MilestoneID) } + if opts.ProjectID > 0 { + sess.Join("INNER", "project_issue", "issue.id = project_issue.issue_id"). + And("project_issue.project_id=?", opts.ProjectID) + } + if opts.AssigneeID > 0 { applyAssigneeCondition(sess, opts.AssigneeID) } diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 98922db808ec..74ba85ca9016 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1303,6 +1303,8 @@ issues.filter_label_exclude = `Use alt + click/enter t issues.filter_label_no_select = All labels issues.filter_milestone = Milestone issues.filter_milestone_no_select = All milestones +issues.filter_project = Project +issues.filter_project_no_select = All projects issues.filter_assignee = Assignee issues.filter_assginee_no_select = All assignees issues.filter_poster = Author diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index edd9821ac783..ed7461bbc669 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -203,6 +203,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti RepoID: repo.ID, Labels: selectLabels, MilestoneID: milestoneID, + ProjectID: projectID, AssigneeID: assigneeID, MentionedID: mentionedID, PosterID: posterID, @@ -362,18 +363,16 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti return 0 } - if ctx.Repo.CanWriteIssuesOrPulls(ctx.Params(":type") == "pulls") { - projects, _, err := project_model.FindProjects(ctx, project_model.SearchOptions{ - RepoID: repo.ID, - Type: project_model.TypeRepository, - IsClosed: util.OptionalBoolOf(isShowClosed), - }) - if err != nil { - ctx.ServerError("GetProjects", err) - return - } - ctx.Data["Projects"] = projects + projects, _, err := project_model.FindProjects(ctx, project_model.SearchOptions{ + RepoID: repo.ID, + Type: project_model.TypeRepository, + IsClosed: util.OptionalBoolOf(isShowClosed), + }) + if err != nil { + ctx.ServerError("FindProjects", err) + return } + ctx.Data["Projects"] = projects ctx.Data["IssueStats"] = issueStats ctx.Data["SelLabelIDs"] = labelIDs @@ -381,6 +380,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti ctx.Data["ViewType"] = viewType ctx.Data["SortType"] = sortType ctx.Data["MilestoneID"] = milestoneID + ctx.Data["ProjectID"] = projectID ctx.Data["AssigneeID"] = assigneeID ctx.Data["PosterID"] = posterID ctx.Data["IsShowClosed"] = isShowClosed @@ -397,6 +397,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti pager.AddParam(ctx, "state", "State") pager.AddParam(ctx, "labels", "SelectLabels") pager.AddParam(ctx, "milestone", "MilestoneID") + pager.AddParam(ctx, "project", "ProjectID") pager.AddParam(ctx, "assignee", "AssigneeID") pager.AddParam(ctx, "poster", "PosterID") ctx.Data["Page"] = pager @@ -2352,6 +2353,8 @@ func SearchIssues(ctx *context.Context) { includedMilestones = strings.Split(milestones, ",") } + projectID := ctx.FormInt64("project") + // this api is also used in UI, // so the default limit is set to fit UI needs limit := ctx.FormInt("limit") @@ -2374,6 +2377,7 @@ func SearchIssues(ctx *context.Context) { IssueIDs: issueIDs, IncludedLabelNames: includedLabelNames, IncludeMilestones: includedMilestones, + ProjectID: projectID, SortType: "priorityrepo", PriorityRepoID: ctx.FormInt64("priority_repo_id"), IsPull: isPull, @@ -2511,6 +2515,8 @@ func ListIssues(ctx *context.Context) { } } + projectID := ctx.FormInt64("project") + listOptions := db.ListOptions{ Page: ctx.FormInt("page"), PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")), @@ -2550,6 +2556,7 @@ func ListIssues(ctx *context.Context) { IssueIDs: issueIDs, LabelIDs: labelIDs, MilestoneIDs: mileIDs, + ProjectID: projectID, IsPull: isPull, UpdatedBeforeUnix: before, UpdatedAfterUnix: since, diff --git a/templates/repo/issue/list.tmpl b/templates/repo/issue/list.tmpl index ad0ce50ec15f..22a6104baa88 100644 --- a/templates/repo/issue/list.tmpl +++ b/templates/repo/issue/list.tmpl @@ -50,9 +50,9 @@ {{.locale.Tr "repo.issues.filter_label_exclude" | Safe}} - {{.locale.Tr "repo.issues.filter_label_no_select"}} + {{.locale.Tr "repo.issues.filter_label_no_select"}} {{range .Labels}} - {{if .IsExcluded}}{{svg "octicon-circle-slash"}}{{else if .IsSelected}}{{svg "octicon-check"}}{{end}} {{.Name | RenderEmoji}} + {{if .IsExcluded}}{{svg "octicon-circle-slash"}}{{else if .IsSelected}}{{svg "octicon-check"}}{{end}} {{.Name | RenderEmoji}} {{end}} @@ -70,7 +70,25 @@ {{.locale.Tr "repo.issues.filter_milestone_no_select"}} {{range .Milestones}} - {{.Name}} + {{.Name}} + {{end}} + + + + + @@ -86,9 +104,9 @@ {{svg "octicon-search" 16}} - {{.locale.Tr "repo.issues.filter_poster_no_select"}} + {{.locale.Tr "repo.issues.filter_poster_no_select"}} {{range .Posters}} - + {{avatar .}} {{.GetDisplayName}} {{end}} @@ -106,9 +124,9 @@ {{svg "octicon-search" 16}} - {{.locale.Tr "repo.issues.filter_assginee_no_select"}} + {{.locale.Tr "repo.issues.filter_assginee_no_select"}} {{range .Assignees}} - + {{avatar .}} {{.GetDisplayName}} {{end}} @@ -123,12 +141,12 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}} @@ -141,14 +159,14 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}} diff --git a/templates/repo/issue/openclose.tmpl b/templates/repo/issue/openclose.tmpl index 758fc447ce60..9299fe1cb1f1 100644 --- a/templates/repo/issue/openclose.tmpl +++ b/templates/repo/issue/openclose.tmpl @@ -1,5 +1,5 @@