Skip to content

Improve milestone filter on issues page #22423

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Apr 30, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion models/db/search.go
Original file line number Diff line number Diff line change
@@ -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
)
8 changes: 6 additions & 2 deletions models/issues/issue.go
Original file line number Diff line number Diff line change
@@ -1273,7 +1273,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")
Comment on lines +1276 to +1277
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name NoConditionID looks really strange. When reading the code:

  1. The parameter is no-condition-ID
  2. The the next line adds a condition .....

Just a nit, just my opinion, not blocker.

} else if len(opts.MilestoneIDs) > 0 {
sess.In("issue.milestone_id", opts.MilestoneIDs)
}

@@ -1287,7 +1289,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")))
}

@@ -1721,6 +1723,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 {
5 changes: 4 additions & 1 deletion options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
@@ -1352,7 +1352,10 @@ issues.filter_label = Label
issues.filter_label_exclude = `Use <code>alt</code> + <code>click/enter</code> 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
31 changes: 24 additions & 7 deletions routers/web/repo/issue.go
Original file line number Diff line number Diff line change
@@ -241,7 +241,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,20 +438,37 @@ func Issues(ctx *context.Context) {
return
}

var err error
renderMilestones(ctx)
if ctx.Written() {
return
}

ctx.Data["CanWriteIssuesOrPulls"] = ctx.Repo.CanWriteIssuesOrPulls(isPullList)

ctx.HTML(http.StatusOK, tplIssues)
}

func renderMilestones(ctx *context.Context) {
// Get milestones
ctx.Data["Milestones"], _, err = issues_model.GetMilestones(issues_model.GetMilestonesOption{
milestones, _, err := issues_model.GetMilestones(issues_model.GetMilestonesOption{
RepoID: ctx.Repo.Repository.ID,
State: api.StateType(ctx.FormString("state")),
State: api.StateAll,
})
if err != nil {
ctx.ServerError("GetAllRepoMilestones", err)
return
}

ctx.Data["CanWriteIssuesOrPulls"] = ctx.Repo.CanWriteIssuesOrPulls(isPullList)

ctx.HTML(http.StatusOK, tplIssues)
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
27 changes: 23 additions & 4 deletions templates/repo/issue/list.tmpl
Original file line number Diff line number Diff line change
@@ -53,7 +53,7 @@
</div>

<!-- Milestone -->
<div class="ui {{if not .Milestones}}disabled{{end}} dropdown jump item">
<div class="ui {{if not (or .OpenMilestones .ClosedMilestones)}}disabled{{end}} dropdown jump item">
<span class="text">
{{.locale.Tr "repo.issues.filter_milestone"}}
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
@@ -63,9 +63,28 @@
<i class="icon gt-df gt-ac gt-jc">{{svg "octicon-search" 16}}</i>
<input type="text" placeholder="{{.locale.Tr "repo.issues.filter_milestone"}}">
</div>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_milestone_no_select"}}</a>
{{range .Milestones}}
<a class="{{if $.MilestoneID}}{{if eq $.MilestoneID .ID}}active selected{{end}}{{end}} item" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{.ID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.Name}}</a>
<div class="divider"></div>
<a class="{{if not $.MilestoneID}}active selected {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone=0&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_milestone_all"}}</a>
<a class="{{if $.MilestoneID}}{{if eq $.MilestoneID -1}}active selected {{end}}{{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone=-1&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_milestone_none"}}</a>
{{if .OpenMilestones}}
<div class="divider"></div>
<div class="header">{{.locale.Tr "repo.issues.filter_milestone_open"}}</div>
{{range .OpenMilestones}}
<a class="{{if $.MilestoneID}}{{if eq $.MilestoneID .ID}}active selected {{end}}{{end}}item" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{.ID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">
{{svg "octicon-milestone" 16 "mr-2"}}
{{.Name}}
</a>
{{end}}
{{end}}
{{if .ClosedMilestones}}
<div class="divider"></div>
<div class="header">{{.locale.Tr "repo.issues.filter_milestone_closed"}}</div>
{{range .ClosedMilestones}}
<a class="{{if $.MilestoneID}}{{if eq $.MilestoneID .ID}}active selected {{end}}{{end}}item" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{.ID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">
{{svg "octicon-milestone" 16 "mr-2"}}
{{.Name}}
</a>
{{end}}
{{end}}
</div>
</div>
39 changes: 39 additions & 0 deletions templates/repo/issue/milestone/select_menu.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<div class="header" style="text-transform: none;font-size:16px;">{{.locale.Tr "repo.issues.new.add_milestone_title"}}</div>
{{if or .OpenMilestones .ClosedMilestones}}
<div class="ui icon search input">
<i class="icon gt-df gt-ac gt-jc">{{svg "octicon-search" 16}}</i>
<input type="text" placeholder="{{.locale.Tr "repo.issues.filter_milestones"}}">
</div>
<div class="divider"></div>
{{end}}
<div class="no-select item">{{.locale.Tr "repo.issues.new.clear_milestone"}}</div>
{{if and (not .OpenMilestones) (not .ClosedMilestones)}}
<div class="header" style="text-transform: none;font-size:14px;">
{{.locale.Tr "repo.issues.new.no_items"}}
</div>
{{else}}
{{if .OpenMilestones}}
<div class="divider"></div>
<div class="header">
{{.locale.Tr "repo.issues.new.open_milestone"}}
</div>
{{range .OpenMilestones}}
<a class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?milestone={{.ID}}">
{{svg "octicon-milestone" 16 "gt-mr-2"}}
{{.Name}}
</a>
{{end}}
{{end}}
{{if .ClosedMilestones}}
<div class="divider"></div>
<div class="header">
{{.locale.Tr "repo.issues.new.closed_milestone"}}
</div>
{{range .ClosedMilestones}}
<a class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?milestone={{.ID}}">
{{svg "octicon-milestone" 16 "gt-mr-2"}}
{{.Name}}
</a>
{{end}}
{{end}}
{{end}}
39 changes: 1 addition & 38 deletions templates/repo/issue/new_form.tmpl
Original file line number Diff line number Diff line change
@@ -72,44 +72,7 @@
{{end}}
</span>
<div class="menu">
<div class="header" style="text-transform: none;font-size:16px;">{{.locale.Tr "repo.issues.new.add_milestone_title"}}</div>
{{if or .OpenMilestones .ClosedMilestones}}
<div class="ui icon search input">
<i class="icon gt-df gt-ac gt-jc">{{svg "octicon-search" 16}}</i>
<input type="text" placeholder="{{.locale.Tr "repo.issues.filter_milestones"}}">
</div>
{{end}}
<div class="no-select item">{{.locale.Tr "repo.issues.new.clear_milestone"}}</div>
{{if and (not .OpenMilestones) (not .ClosedMilestones)}}
<div class="header" style="text-transform: none;font-size:14px;">
{{.locale.Tr "repo.issues.new.no_items"}}
</div>
{{else}}
{{if .OpenMilestones}}
<div class="divider"></div>
<div class="header">
{{.locale.Tr "repo.issues.new.open_milestone"}}
</div>
{{range .OpenMilestones}}
<a class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?milestone={{.ID}}">
{{svg "octicon-milestone" 16 "gt-mr-2"}}
{{.Name}}
</a>
{{end}}
{{end}}
{{if .ClosedMilestones}}
<div class="divider"></div>
<div class="header">
{{.locale.Tr "repo.issues.new.closed_milestone"}}
</div>
{{range .ClosedMilestones}}
<a class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?milestone={{.ID}}">
{{svg "octicon-milestone" 16 "gt-mr-2"}}
{{.Name}}
</a>
{{end}}
{{end}}
{{end}}
{{template "repo/issue/milestone/select_menu" .}}
</div>
</div>
<div class="ui select-milestone list">
39 changes: 1 addition & 38 deletions templates/repo/issue/view_content/sidebar.tmpl
Original file line number Diff line number Diff line change
@@ -118,44 +118,7 @@
{{end}}
</a>
<div class="menu" data-action="update" data-issue-id="{{$.Issue.ID}}" data-update-url="{{$.RepoLink}}/issues/milestone">
<div class="header" style="text-transform: none;font-size:16px;">{{.locale.Tr "repo.issues.new.add_milestone_title"}}</div>
{{if or .OpenMilestones .ClosedMilestones}}
<div class="ui icon search input">
<i class="icon gt-df gt-ac gt-jc">{{svg "octicon-search" 16}}</i>
<input type="text" placeholder="{{.locale.Tr "repo.issues.filter_milestones"}}">
</div>
{{end}}
<div class="no-select item">{{.locale.Tr "repo.issues.new.clear_milestone"}}</div>
{{if and (not .OpenMilestones) (not .ClosedMilestones)}}
<div class="header" style="text-transform: none;font-size:14px;">
{{.locale.Tr "repo.issues.new.no_items"}}
</div>
{{else}}
{{if .OpenMilestones}}
<div class="divider"></div>
<div class="header">
{{.locale.Tr "repo.issues.new.open_milestone"}}
</div>
{{range .OpenMilestones}}
<a class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?milestone={{.ID}}">
{{svg "octicon-milestone" 16 "gt-mr-2"}}
{{.Name}}
</a>
{{end}}
{{end}}
{{if .ClosedMilestones}}
<div class="divider"></div>
<div class="header">
{{.locale.Tr "repo.issues.new.closed_milestone"}}
</div>
{{range .ClosedMilestones}}
<a class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?milestone={{.ID}}">
{{svg "octicon-milestone" 16 "gt-mr-2"}}
{{.Name}}
</a>
{{end}}
{{end}}
{{end}}
{{template "repo/issue/milestone/select_menu" .}}
</div>
</div>
<div class="ui select-milestone list">