diff --git a/models/db/search.go b/models/db/search.go index 26e082756a..105cb64c41 100644 --- a/models/db/search.go +++ b/models/db/search.go @@ -31,5 +31,5 @@ const ( const ( // Which means a condition to filter the records which don't match any id. // It's different from zero which means the condition could be ignored. - NoneID = -1 + NoConditionID = -1 ) diff --git a/models/issues/issue.go b/models/issues/issue.go index c8d148dd86..2dae8848c2 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -1266,7 +1266,9 @@ func (opts *IssuesOptions) setupSessionNoLimit(sess *xorm.Session) { applySubscribedCondition(sess, opts.SubscriberID) } - if len(opts.MilestoneIDs) > 0 { + if len(opts.MilestoneIDs) == 1 && opts.MilestoneIDs[0] == db.NoConditionID { + sess.And("issue.milestone_id = 0") + } else if len(opts.MilestoneIDs) > 0 { sess.In("issue.milestone_id", opts.MilestoneIDs) } @@ -1280,7 +1282,7 @@ func (opts *IssuesOptions) setupSessionNoLimit(sess *xorm.Session) { if opts.ProjectID > 0 { sess.Join("INNER", "project_issue", "issue.id = project_issue.issue_id"). And("project_issue.project_id=?", opts.ProjectID) - } else if opts.ProjectID == db.NoneID { // show those that are in no project + } else if opts.ProjectID == db.NoConditionID { // show those that are in no project sess.And(builder.NotIn("issue.id", builder.Select("issue_id").From("project_issue"))) } @@ -1680,6 +1682,8 @@ func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats, if opts.MilestoneID > 0 { sess.And("issue.milestone_id = ?", opts.MilestoneID) + } else if opts.MilestoneID == db.NoConditionID { + sess.And("issue.milestone_id = 0") } if opts.ProjectID > 0 { diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 5154aadb68..8169cba108 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1310,7 +1310,10 @@ issues.filter_label = Label issues.filter_label_exclude = `Use alt + click/enter to exclude labels` issues.filter_label_no_select = All labels issues.filter_milestone = Milestone -issues.filter_milestone_no_select = All milestones +issues.filter_milestone_all = All milestones +issues.filter_milestone_none = No milestones +issues.filter_milestone_open = Open milestones +issues.filter_milestone_closed = Closed milestones issues.filter_project = Project issues.filter_project_all = All projects issues.filter_project_none = No project diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 3868e895f0..4f370c610d 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -237,7 +237,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti pager := context.NewPagination(total, setting.UI.IssuePagingNum, page, 5) var mileIDs []int64 - if milestoneID > 0 { + if milestoneID > 0 || milestoneID == db.NoConditionID { // -1 to get those issues which have no any milestone assigned mileIDs = []int64{milestoneID} } @@ -438,14 +438,8 @@ func Issues(ctx *context.Context) { return } - var err error - // Get milestones - ctx.Data["Milestones"], _, err = issues_model.GetMilestones(issues_model.GetMilestonesOption{ - RepoID: ctx.Repo.Repository.ID, - State: api.StateType(ctx.FormString("state")), - }) - if err != nil { - ctx.ServerError("GetAllRepoMilestones", err) + renderMilestones(ctx) + if ctx.Written() { return } @@ -454,6 +448,29 @@ func Issues(ctx *context.Context) { ctx.HTML(http.StatusOK, tplIssues) } +func renderMilestones(ctx *context.Context) { + // Get milestones + milestones, _, err := issues_model.GetMilestones(issues_model.GetMilestonesOption{ + RepoID: ctx.Repo.Repository.ID, + State: api.StateAll, + }) + if err != nil { + ctx.ServerError("GetAllRepoMilestones", err) + return + } + + openMilestones, closedMilestones := issues_model.MilestoneList{}, issues_model.MilestoneList{} + for _, milestone := range milestones { + if milestone.IsClosed { + closedMilestones = append(closedMilestones, milestone) + } else { + openMilestones = append(openMilestones, milestone) + } + } + ctx.Data["OpenMilestones"] = openMilestones + ctx.Data["ClosedMilestones"] = closedMilestones +} + // RetrieveRepoMilestonesAndAssignees find all the milestones and assignees of a repository func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *repo_model.Repository) { var err error diff --git a/templates/repo/issue/list.tmpl b/templates/repo/issue/list.tmpl index ddc197a889..a594801093 100644 --- a/templates/repo/issue/list.tmpl +++ b/templates/repo/issue/list.tmpl @@ -63,7 +63,7 @@ - diff --git a/templates/repo/issue/milestone/select_menu.tmpl b/templates/repo/issue/milestone/select_menu.tmpl new file mode 100644 index 0000000000..6f67b5d523 --- /dev/null +++ b/templates/repo/issue/milestone/select_menu.tmpl @@ -0,0 +1,39 @@ +
{{.locale.Tr "repo.issues.new.add_milestone_title"}}
+{{if or .OpenMilestones .ClosedMilestones}} + +
+{{end}} +
{{.locale.Tr "repo.issues.new.clear_milestone"}}
+{{if and (not .OpenMilestones) (not .ClosedMilestones)}} +
+ {{.locale.Tr "repo.issues.new.no_items"}} +
+{{else}} + {{if .OpenMilestones}} +
+
+ {{.locale.Tr "repo.issues.new.open_milestone"}} +
+ {{range .OpenMilestones}} + + {{svg "octicon-milestone" 16 "gt-mr-2"}} + {{.Name}} + + {{end}} + {{end}} + {{if .ClosedMilestones}} +
+
+ {{.locale.Tr "repo.issues.new.closed_milestone"}} +
+ {{range .ClosedMilestones}} + + {{svg "octicon-milestone" 16 "gt-mr-2"}} + {{.Name}} + + {{end}} + {{end}} +{{end}} diff --git a/templates/repo/issue/new_form.tmpl b/templates/repo/issue/new_form.tmpl index c21d0c1689..25d09cf2bc 100644 --- a/templates/repo/issue/new_form.tmpl +++ b/templates/repo/issue/new_form.tmpl @@ -93,44 +93,7 @@ {{end}}
diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index 0d796af0f3..8b788d646d 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -161,44 +161,7 @@ {{end}}