mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-22 15:13:54 +01:00
Add dashboard milestone search and repo milestone search by name (#14866)
Feature for issue #13845: - Add milestones search by name on dashboard milestones page. - Add milestones search by name on repo issue/milestones page.
This commit is contained in:
parent
0d1a5e0ffc
commit
fa06e98553
5 changed files with 165 additions and 58 deletions
|
@ -426,9 +426,12 @@ func GetMilestones(opts GetMilestonesOption) (MilestoneList, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchMilestones search milestones
|
// SearchMilestones search milestones
|
||||||
func SearchMilestones(repoCond builder.Cond, page int, isClosed bool, sortType string) (MilestoneList, error) {
|
func SearchMilestones(repoCond builder.Cond, page int, isClosed bool, sortType string, keyword string) (MilestoneList, error) {
|
||||||
miles := make([]*Milestone, 0, setting.UI.IssuePagingNum)
|
miles := make([]*Milestone, 0, setting.UI.IssuePagingNum)
|
||||||
sess := x.Where("is_closed = ?", isClosed)
|
sess := x.Where("is_closed = ?", isClosed)
|
||||||
|
if len(keyword) > 0 {
|
||||||
|
sess = sess.And(builder.Like{"UPPER(name)", strings.ToUpper(keyword)})
|
||||||
|
}
|
||||||
if repoCond.IsValid() {
|
if repoCond.IsValid() {
|
||||||
sess.In("repo_id", builder.Select("id").From("repository").Where(repoCond))
|
sess.In("repo_id", builder.Select("id").From("repository").Where(repoCond))
|
||||||
}
|
}
|
||||||
|
@ -460,6 +463,7 @@ func GetMilestonesByRepoIDs(repoIDs []int64, page int, isClosed bool, sortType s
|
||||||
page,
|
page,
|
||||||
isClosed,
|
isClosed,
|
||||||
sortType,
|
sortType,
|
||||||
|
"",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -506,6 +510,38 @@ func GetMilestonesStatsByRepoCond(repoCond builder.Cond) (*MilestonesStats, erro
|
||||||
return stats, nil
|
return stats, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMilestonesStatsByRepoCondAndKw returns milestone statistic information for dashboard by given repo conditions and name keyword.
|
||||||
|
func GetMilestonesStatsByRepoCondAndKw(repoCond builder.Cond, keyword string) (*MilestonesStats, error) {
|
||||||
|
var err error
|
||||||
|
stats := &MilestonesStats{}
|
||||||
|
|
||||||
|
sess := x.Where("is_closed = ?", false)
|
||||||
|
if len(keyword) > 0 {
|
||||||
|
sess = sess.And(builder.Like{"UPPER(name)", strings.ToUpper(keyword)})
|
||||||
|
}
|
||||||
|
if repoCond.IsValid() {
|
||||||
|
sess.And(builder.In("repo_id", builder.Select("id").From("repository").Where(repoCond)))
|
||||||
|
}
|
||||||
|
stats.OpenCount, err = sess.Count(new(Milestone))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sess = x.Where("is_closed = ?", true)
|
||||||
|
if len(keyword) > 0 {
|
||||||
|
sess = sess.And(builder.Like{"UPPER(name)", strings.ToUpper(keyword)})
|
||||||
|
}
|
||||||
|
if repoCond.IsValid() {
|
||||||
|
sess.And(builder.In("repo_id", builder.Select("id").From("repository").Where(repoCond)))
|
||||||
|
}
|
||||||
|
stats.ClosedCount, err = sess.Count(new(Milestone))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return stats, nil
|
||||||
|
}
|
||||||
|
|
||||||
func countRepoMilestones(e Engine, repoID int64) (int64, error) {
|
func countRepoMilestones(e Engine, repoID int64) (int64, error) {
|
||||||
return e.
|
return e.
|
||||||
Where("repo_id=?", repoID).
|
Where("repo_id=?", repoID).
|
||||||
|
@ -548,6 +584,34 @@ func CountMilestonesByRepoCond(repoCond builder.Cond, isClosed bool) (map[int64]
|
||||||
return countMap, nil
|
return countMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CountMilestonesByRepoCondAndKw map from repo conditions and the keyword of milestones' name to number of milestones matching the options`
|
||||||
|
func CountMilestonesByRepoCondAndKw(repoCond builder.Cond, keyword string, isClosed bool) (map[int64]int64, error) {
|
||||||
|
sess := x.Where("is_closed = ?", isClosed)
|
||||||
|
if len(keyword) > 0 {
|
||||||
|
sess = sess.And(builder.Like{"UPPER(name)", strings.ToUpper(keyword)})
|
||||||
|
}
|
||||||
|
if repoCond.IsValid() {
|
||||||
|
sess.In("repo_id", builder.Select("id").From("repository").Where(repoCond))
|
||||||
|
}
|
||||||
|
|
||||||
|
countsSlice := make([]*struct {
|
||||||
|
RepoID int64
|
||||||
|
Count int64
|
||||||
|
}, 0, 10)
|
||||||
|
if err := sess.GroupBy("repo_id").
|
||||||
|
Select("repo_id AS repo_id, COUNT(*) AS count").
|
||||||
|
Table("milestone").
|
||||||
|
Find(&countsSlice); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
countMap := make(map[int64]int64, len(countsSlice))
|
||||||
|
for _, c := range countsSlice {
|
||||||
|
countMap[c.RepoID] = c.Count
|
||||||
|
}
|
||||||
|
return countMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
func updateRepoMilestoneNum(e Engine, repoID int64) error {
|
func updateRepoMilestoneNum(e Engine, repoID int64) error {
|
||||||
_, err := e.Exec("UPDATE `repository` SET num_milestones=(SELECT count(*) FROM milestone WHERE repo_id=?),num_closed_milestones=(SELECT count(*) FROM milestone WHERE repo_id=? AND is_closed=?) WHERE id=?",
|
_, err := e.Exec("UPDATE `repository` SET num_milestones=(SELECT count(*) FROM milestone WHERE repo_id=?),num_closed_milestones=(SELECT count(*) FROM milestone WHERE repo_id=? AND is_closed=?) WHERE id=?",
|
||||||
repoID,
|
repoID,
|
||||||
|
|
|
@ -6,6 +6,7 @@ package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
|
@ -44,6 +45,9 @@ func Milestones(ctx *context.Context) {
|
||||||
ctx.Data["ClosedCount"] = stats.ClosedCount
|
ctx.Data["ClosedCount"] = stats.ClosedCount
|
||||||
|
|
||||||
sortType := ctx.Query("sort")
|
sortType := ctx.Query("sort")
|
||||||
|
|
||||||
|
keyword := strings.Trim(ctx.Query("q"), " ")
|
||||||
|
|
||||||
page := ctx.QueryInt("page")
|
page := ctx.QueryInt("page")
|
||||||
if page <= 1 {
|
if page <= 1 {
|
||||||
page = 1
|
page = 1
|
||||||
|
@ -67,6 +71,7 @@ func Milestones(ctx *context.Context) {
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
State: state,
|
State: state,
|
||||||
SortType: sortType,
|
SortType: sortType,
|
||||||
|
Name: keyword,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetMilestones", err)
|
ctx.ServerError("GetMilestones", err)
|
||||||
|
@ -90,10 +95,12 @@ func Milestones(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data["SortType"] = sortType
|
ctx.Data["SortType"] = sortType
|
||||||
|
ctx.Data["Keyword"] = keyword
|
||||||
ctx.Data["IsShowClosed"] = isShowClosed
|
ctx.Data["IsShowClosed"] = isShowClosed
|
||||||
|
|
||||||
pager := context.NewPagination(total, setting.UI.IssuePagingNum, page, 5)
|
pager := context.NewPagination(total, setting.UI.IssuePagingNum, page, 5)
|
||||||
pager.AddParam(ctx, "state", "State")
|
pager.AddParam(ctx, "state", "State")
|
||||||
|
pager.AddParam(ctx, "q", "Keyword")
|
||||||
ctx.Data["Page"] = pager
|
ctx.Data["Page"] = pager
|
||||||
|
|
||||||
ctx.HTML(http.StatusOK, tplMilestone)
|
ctx.HTML(http.StatusOK, tplMilestone)
|
||||||
|
|
|
@ -202,6 +202,7 @@ func Milestones(ctx *context.Context) {
|
||||||
isShowClosed = ctx.Query("state") == "closed"
|
isShowClosed = ctx.Query("state") == "closed"
|
||||||
sortType = ctx.Query("sort")
|
sortType = ctx.Query("sort")
|
||||||
page = ctx.QueryInt("page")
|
page = ctx.QueryInt("page")
|
||||||
|
keyword = strings.Trim(ctx.Query("q"), " ")
|
||||||
)
|
)
|
||||||
|
|
||||||
if page <= 1 {
|
if page <= 1 {
|
||||||
|
@ -234,15 +235,15 @@ func Milestones(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
counts, err := models.CountMilestonesByRepoCond(userRepoCond, isShowClosed)
|
counts, err := models.CountMilestonesByRepoCondAndKw(userRepoCond, keyword, isShowClosed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("CountMilestonesByRepoIDs", err)
|
ctx.ServerError("CountMilestonesByRepoIDs", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
milestones, err := models.SearchMilestones(repoCond, page, isShowClosed, sortType)
|
milestones, err := models.SearchMilestones(repoCond, page, isShowClosed, sortType, keyword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetMilestonesByRepoIDs", err)
|
ctx.ServerError("SearchMilestones", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,7 +278,7 @@ func Milestones(ctx *context.Context) {
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
milestoneStats, err := models.GetMilestonesStatsByRepoCond(repoCond)
|
milestoneStats, err := models.GetMilestonesStatsByRepoCondAndKw(repoCond, keyword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetMilestoneStats", err)
|
ctx.ServerError("GetMilestoneStats", err)
|
||||||
return
|
return
|
||||||
|
@ -287,7 +288,7 @@ func Milestones(ctx *context.Context) {
|
||||||
if len(repoIDs) == 0 {
|
if len(repoIDs) == 0 {
|
||||||
totalMilestoneStats = milestoneStats
|
totalMilestoneStats = milestoneStats
|
||||||
} else {
|
} else {
|
||||||
totalMilestoneStats, err = models.GetMilestonesStatsByRepoCond(userRepoCond)
|
totalMilestoneStats, err = models.GetMilestonesStatsByRepoCondAndKw(userRepoCond, keyword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetMilestoneStats", err)
|
ctx.ServerError("GetMilestoneStats", err)
|
||||||
return
|
return
|
||||||
|
@ -310,12 +311,14 @@ func Milestones(ctx *context.Context) {
|
||||||
ctx.Data["Counts"] = counts
|
ctx.Data["Counts"] = counts
|
||||||
ctx.Data["MilestoneStats"] = milestoneStats
|
ctx.Data["MilestoneStats"] = milestoneStats
|
||||||
ctx.Data["SortType"] = sortType
|
ctx.Data["SortType"] = sortType
|
||||||
|
ctx.Data["Keyword"] = keyword
|
||||||
if milestoneStats.Total() != totalMilestoneStats.Total() {
|
if milestoneStats.Total() != totalMilestoneStats.Total() {
|
||||||
ctx.Data["RepoIDs"] = repoIDs
|
ctx.Data["RepoIDs"] = repoIDs
|
||||||
}
|
}
|
||||||
ctx.Data["IsShowClosed"] = isShowClosed
|
ctx.Data["IsShowClosed"] = isShowClosed
|
||||||
|
|
||||||
pager := context.NewPagination(pagerCount, setting.UI.IssuePagingNum, page, 5)
|
pager := context.NewPagination(pagerCount, setting.UI.IssuePagingNum, page, 5)
|
||||||
|
pager.AddParam(ctx, "q", "Keyword")
|
||||||
pager.AddParam(ctx, "repos", "RepoIDs")
|
pager.AddParam(ctx, "repos", "RepoIDs")
|
||||||
pager.AddParam(ctx, "sort", "SortType")
|
pager.AddParam(ctx, "sort", "SortType")
|
||||||
pager.AddParam(ctx, "state", "State")
|
pager.AddParam(ctx, "state", "State")
|
||||||
|
|
|
@ -12,34 +12,52 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<div class="ui compact tiny menu">
|
|
||||||
<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/milestones?state=open">
|
|
||||||
{{svg "octicon-milestone" 16 "mr-3"}}
|
|
||||||
{{.i18n.Tr "repo.milestones.open_tab" .OpenCount}}
|
|
||||||
</a>
|
|
||||||
<a class="item{{if .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/milestones?state=closed">
|
|
||||||
{{svg "octicon-milestone" 16 "mr-3"}}
|
|
||||||
{{.i18n.Tr "repo.milestones.close_tab" .ClosedCount}}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="ui right floated secondary filter menu">
|
<div class="ui three column stackable grid">
|
||||||
<!-- Sort -->
|
<div class="column">
|
||||||
<div class="ui dropdown type jump item">
|
<div class="ui compact tiny menu">
|
||||||
<span class="text">
|
<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/milestones?state=open&q={{$.Keyword}}">
|
||||||
{{.i18n.Tr "repo.issues.filter_sort"}}
|
{{svg "octicon-milestone" 16 "mr-3"}}
|
||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{.i18n.Tr "repo.milestones.open_tab" .OpenCount}}
|
||||||
</span>
|
</a>
|
||||||
<div class="menu">
|
<a class="item{{if .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/milestones?state=closed&q={{$.Keyword}}">
|
||||||
<a class="{{if or (eq .SortType "closestduedate") (not .SortType)}}active{{end}} item" href="{{$.Link}}?sort=closestduedate&state={{$.State}}">{{.i18n.Tr "repo.milestones.filter_sort.closest_due_date"}}</a>
|
{{svg "octicon-milestone" 16 "mr-3"}}
|
||||||
<a class="{{if eq .SortType "furthestduedate"}}active{{end}} item" href="{{$.Link}}?sort=furthestduedate&state={{$.State}}">{{.i18n.Tr "repo.milestones.filter_sort.furthest_due_date"}}</a>
|
{{.i18n.Tr "repo.milestones.close_tab" .ClosedCount}}
|
||||||
<a class="{{if eq .SortType "leastcomplete"}}active{{end}} item" href="{{$.Link}}?sort=leastcomplete&state={{$.State}}">{{.i18n.Tr "repo.milestones.filter_sort.least_complete"}}</a>
|
</a>
|
||||||
<a class="{{if eq .SortType "mostcomplete"}}active{{end}} item" href="{{$.Link}}?sort=mostcomplete&state={{$.State}}">{{.i18n.Tr "repo.milestones.filter_sort.most_complete"}}</a>
|
</div>
|
||||||
<a class="{{if eq .SortType "mostissues"}}active{{end}} item" href="{{$.Link}}?sort=mostissues&state={{$.State}}">{{.i18n.Tr "repo.milestones.filter_sort.most_issues"}}</a>
|
</div>
|
||||||
<a class="{{if eq .SortType "leastissues"}}active{{end}} item" href="{{$.Link}}?sort=leastissues&state={{$.State}}">{{.i18n.Tr "repo.milestones.filter_sort.least_issues"}}</a>
|
|
||||||
|
<!-- Search -->
|
||||||
|
<div class="column center aligned">
|
||||||
|
<form class="ui form ignore-dirty">
|
||||||
|
<div class="ui search fluid action input">
|
||||||
|
<input type="hidden" name="state" value="{{$.State}}"/>
|
||||||
|
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}...">
|
||||||
|
<button class="ui blue button" type="submit">{{.i18n.Tr "explore.search"}}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="column right aligned df ac je">
|
||||||
|
<!-- Sort -->
|
||||||
|
<div class="ui dropdown type jump item">
|
||||||
|
<span class="text">
|
||||||
|
{{.i18n.Tr "repo.issues.filter_sort"}}
|
||||||
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
|
</span>
|
||||||
|
<div class="menu">
|
||||||
|
<a class="{{if or (eq .SortType "closestduedate") (not .SortType)}}active{{end}} item" href="{{$.Link}}?sort=closestduedate&state={{$.State}}&q={{$.Keyword}}">{{.i18n.Tr "repo.milestones.filter_sort.closest_due_date"}}</a>
|
||||||
|
<a class="{{if eq .SortType "furthestduedate"}}active{{end}} item" href="{{$.Link}}?sort=furthestduedate&state={{$.State}}&q={{$.Keyword}}">{{.i18n.Tr "repo.milestones.filter_sort.furthest_due_date"}}</a>
|
||||||
|
<a class="{{if eq .SortType "leastcomplete"}}active{{end}} item" href="{{$.Link}}?sort=leastcomplete&state={{$.State}}&q={{$.Keyword}}">{{.i18n.Tr "repo.milestones.filter_sort.least_complete"}}</a>
|
||||||
|
<a class="{{if eq .SortType "mostcomplete"}}active{{end}} item" href="{{$.Link}}?sort=mostcomplete&state={{$.State}}&q={{$.Keyword}}">{{.i18n.Tr "repo.milestones.filter_sort.most_complete"}}</a>
|
||||||
|
<a class="{{if eq .SortType "mostissues"}}active{{end}} item" href="{{$.Link}}?sort=mostissues&state={{$.State}}&q={{$.Keyword}}">{{.i18n.Tr "repo.milestones.filter_sort.most_issues"}}</a>
|
||||||
|
<a class="{{if eq .SortType "leastissues"}}active{{end}} item" href="{{$.Link}}?sort=leastissues&state={{$.State}}&q={{$.Keyword}}">{{.i18n.Tr "repo.milestones.filter_sort.least_issues"}}</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- milestone list -->
|
||||||
<div class="milestone list">
|
<div class="milestone list">
|
||||||
{{range .Milestones}}
|
{{range .Milestones}}
|
||||||
<li class="item">
|
<li class="item">
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<div class="ui stackable grid">
|
<div class="ui stackable grid">
|
||||||
<div class="four wide column">
|
<div class="four wide column">
|
||||||
<div class="ui secondary vertical filter menu">
|
<div class="ui secondary vertical filter menu">
|
||||||
<a class="item" href="{{.Link}}?type=your_repositories&sort={{$.SortType}}&state={{.State}}">
|
<a class="item" href="{{.Link}}?type=your_repositories&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}">
|
||||||
{{.i18n.Tr "home.issues.in_your_repos"}}
|
{{.i18n.Tr "home.issues.in_your_repos"}}
|
||||||
<strong class="ui right">{{.Total}}</strong>
|
<strong class="ui right">{{.Total}}</strong>
|
||||||
</a>
|
</a>
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
{{$Repo.ID}}%2C
|
{{$Repo.ID}}%2C
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
]&sort={{$.SortType}}&state={{$.State}}" title="{{.FullName}}">
|
]&sort={{$.SortType}}&state={{$.State}}&q={{$.Keyword}}" title="{{.FullName}}">
|
||||||
<span class="text truncate">{{$Repo.FullName}}</span>
|
<span class="text truncate">{{$Repo.FullName}}</span>
|
||||||
<div class="ui {{if $.IsShowClosed}}red{{else}}green{{end}} label">{{index $.Counts $Repo.ID}}</div>
|
<div class="ui {{if $.IsShowClosed}}red{{else}}green{{end}} label">{{index $.Counts $Repo.ID}}</div>
|
||||||
</a>
|
</a>
|
||||||
|
@ -34,34 +34,49 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="twelve wide column content">
|
<div class="twelve wide column content">
|
||||||
<div class="ui compact tiny menu">
|
<div class="ui three column stackable grid">
|
||||||
<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state=open">
|
<div class="column">
|
||||||
{{svg "octicon-issue-opened" 16 "mr-3"}}
|
<div class="ui compact tiny menu">
|
||||||
{{.i18n.Tr "repo.milestones.open_tab" .MilestoneStats.OpenCount}}
|
<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state=open&q={{$.Keyword}}">
|
||||||
</a>
|
{{svg "octicon-issue-opened" 16 "mr-3"}}
|
||||||
<a class="item{{if .IsShowClosed}} active{{end}}" href="{{.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state=closed">
|
{{.i18n.Tr "repo.milestones.open_tab" .MilestoneStats.OpenCount}}
|
||||||
{{svg "octicon-issue-closed" 16 "mr-3"}}
|
</a>
|
||||||
{{.i18n.Tr "repo.milestones.close_tab" .MilestoneStats.ClosedCount}}
|
<a class="item{{if .IsShowClosed}} active{{end}}" href="{{.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state=closed&q={{$.Keyword}}">
|
||||||
</a>
|
{{svg "octicon-issue-closed" 16 "mr-3"}}
|
||||||
</div>
|
{{.i18n.Tr "repo.milestones.close_tab" .MilestoneStats.ClosedCount}}
|
||||||
<div class="ui right floated secondary filter menu">
|
</a>
|
||||||
<!-- Sort -->
|
|
||||||
<div class="ui dropdown type jump item">
|
|
||||||
<span class="text">
|
|
||||||
{{.i18n.Tr "repo.issues.filter_sort"}}
|
|
||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
|
||||||
</span>
|
|
||||||
<div class="menu">
|
|
||||||
<a class="{{if or (eq .SortType "closestduedate") (not .SortType)}}active{{end}} item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=closestduedate&state={{$.State}}">{{.i18n.Tr "repo.milestones.filter_sort.closest_due_date"}}</a>
|
|
||||||
<a class="{{if eq .SortType "furthestduedate"}}active{{end}} item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=furthestduedate&state={{$.State}}">{{.i18n.Tr "repo.milestones.filter_sort.furthest_due_date"}}</a>
|
|
||||||
<a class="{{if eq .SortType "leastcomplete"}}active{{end}} item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=leastcomplete&state={{$.State}}">{{.i18n.Tr "repo.milestones.filter_sort.least_complete"}}</a>
|
|
||||||
<a class="{{if eq .SortType "mostcomplete"}}active{{end}} item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=mostcomplete&state={{$.State}}">{{.i18n.Tr "repo.milestones.filter_sort.most_complete"}}</a>
|
|
||||||
<a class="{{if eq .SortType "mostissues"}}active{{end}} item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=mostissues&state={{$.State}}">{{.i18n.Tr "repo.milestones.filter_sort.most_issues"}}</a>
|
|
||||||
<a class="{{if eq .SortType "leastissues"}}active{{end}} item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=leastissues&state={{$.State}}">{{.i18n.Tr "repo.milestones.filter_sort.least_issues"}}</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="column center aligned">
|
||||||
|
<form class="ui form ignore-dirty">
|
||||||
|
<div class="ui search fluid action input">
|
||||||
|
<input type="hidden" name="type" value="{{$.ViewType}}"/>
|
||||||
|
<input type="hidden" name="repos" value="[{{range $.RepoIDs}}{{.}},{{end}}]"/>
|
||||||
|
<input type="hidden" name="sort" value="{{$.SortType}}"/>
|
||||||
|
<input type="hidden" name="state" value="{{$.State}}"/>
|
||||||
|
<input name="q" value="{{$.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}...">
|
||||||
|
<button class="ui blue button" type="submit">{{.i18n.Tr "explore.search"}}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="column right aligned df ac je">
|
||||||
|
<!-- Sort -->
|
||||||
|
<div class="ui dropdown type jump item">
|
||||||
|
<span class="text">
|
||||||
|
{{.i18n.Tr "repo.issues.filter_sort"}}
|
||||||
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
|
</span>
|
||||||
|
<div class="menu">
|
||||||
|
<a class="{{if or (eq .SortType "closestduedate") (not .SortType)}}active{{end}} item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=closestduedate&state={{$.State}}&q={{$.Keyword}}">{{.i18n.Tr "repo.milestones.filter_sort.closest_due_date"}}</a>
|
||||||
|
<a class="{{if eq .SortType "furthestduedate"}}active{{end}} item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=furthestduedate&state={{$.State}}&q={{$.Keyword}}">{{.i18n.Tr "repo.milestones.filter_sort.furthest_due_date"}}</a>
|
||||||
|
<a class="{{if eq .SortType "leastcomplete"}}active{{end}} item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=leastcomplete&state={{$.State}}&q={{$.Keyword}}">{{.i18n.Tr "repo.milestones.filter_sort.least_complete"}}</a>
|
||||||
|
<a class="{{if eq .SortType "mostcomplete"}}active{{end}} item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=mostcomplete&state={{$.State}}&q={{$.Keyword}}">{{.i18n.Tr "repo.milestones.filter_sort.most_complete"}}</a>
|
||||||
|
<a class="{{if eq .SortType "mostissues"}}active{{end}} item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=mostissues&state={{$.State}}&q={{$.Keyword}}">{{.i18n.Tr "repo.milestones.filter_sort.most_issues"}}</a>
|
||||||
|
<a class="{{if eq .SortType "leastissues"}}active{{end}} item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=leastissues&state={{$.State}}&q={{$.Keyword}}">{{.i18n.Tr "repo.milestones.filter_sort.least_issues"}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="milestone list">
|
<div class="milestone list">
|
||||||
{{range .Milestones}}
|
{{range .Milestones}}
|
||||||
<li class="item">
|
<li class="item">
|
||||||
|
|
Loading…
Reference in a new issue