forked from gitea/gitea
		
	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
					
				| @ -426,9 +426,12 @@ func GetMilestones(opts GetMilestonesOption) (MilestoneList, error) { | ||||
| } | ||||
| 
 | ||||
| // 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) | ||||
| 	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)) | ||||
| 	} | ||||
| @ -460,6 +463,7 @@ func GetMilestonesByRepoIDs(repoIDs []int64, page int, isClosed bool, sortType s | ||||
| 		page, | ||||
| 		isClosed, | ||||
| 		sortType, | ||||
| 		"", | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
| @ -506,6 +510,38 @@ func GetMilestonesStatsByRepoCond(repoCond builder.Cond) (*MilestonesStats, erro | ||||
| 	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) { | ||||
| 	return e. | ||||
| 		Where("repo_id=?", repoID). | ||||
| @ -548,6 +584,34 @@ func CountMilestonesByRepoCond(repoCond builder.Cond, isClosed bool) (map[int64] | ||||
| 	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 { | ||||
| 	_, 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, | ||||
|  | ||||
| @ -6,6 +6,7 @@ package repo | ||||
| 
 | ||||
| import ( | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"code.gitea.io/gitea/models" | ||||
| @ -44,6 +45,9 @@ func Milestones(ctx *context.Context) { | ||||
| 	ctx.Data["ClosedCount"] = stats.ClosedCount | ||||
| 
 | ||||
| 	sortType := ctx.Query("sort") | ||||
| 
 | ||||
| 	keyword := strings.Trim(ctx.Query("q"), " ") | ||||
| 
 | ||||
| 	page := ctx.QueryInt("page") | ||||
| 	if page <= 1 { | ||||
| 		page = 1 | ||||
| @ -67,6 +71,7 @@ func Milestones(ctx *context.Context) { | ||||
| 		RepoID:   ctx.Repo.Repository.ID, | ||||
| 		State:    state, | ||||
| 		SortType: sortType, | ||||
| 		Name:     keyword, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		ctx.ServerError("GetMilestones", err) | ||||
| @ -90,10 +95,12 @@ func Milestones(ctx *context.Context) { | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.Data["SortType"] = sortType | ||||
| 	ctx.Data["Keyword"] = keyword | ||||
| 	ctx.Data["IsShowClosed"] = isShowClosed | ||||
| 
 | ||||
| 	pager := context.NewPagination(total, setting.UI.IssuePagingNum, page, 5) | ||||
| 	pager.AddParam(ctx, "state", "State") | ||||
| 	pager.AddParam(ctx, "q", "Keyword") | ||||
| 	ctx.Data["Page"] = pager | ||||
| 
 | ||||
| 	ctx.HTML(http.StatusOK, tplMilestone) | ||||
|  | ||||
| @ -202,6 +202,7 @@ func Milestones(ctx *context.Context) { | ||||
| 		isShowClosed = ctx.Query("state") == "closed" | ||||
| 		sortType     = ctx.Query("sort") | ||||
| 		page         = ctx.QueryInt("page") | ||||
| 		keyword      = strings.Trim(ctx.Query("q"), " ") | ||||
| 	) | ||||
| 
 | ||||
| 	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 { | ||||
| 		ctx.ServerError("CountMilestonesByRepoIDs", err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	milestones, err := models.SearchMilestones(repoCond, page, isShowClosed, sortType) | ||||
| 	milestones, err := models.SearchMilestones(repoCond, page, isShowClosed, sortType, keyword) | ||||
| 	if err != nil { | ||||
| 		ctx.ServerError("GetMilestonesByRepoIDs", err) | ||||
| 		ctx.ServerError("SearchMilestones", err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| @ -277,7 +278,7 @@ func Milestones(ctx *context.Context) { | ||||
| 		i++ | ||||
| 	} | ||||
| 
 | ||||
| 	milestoneStats, err := models.GetMilestonesStatsByRepoCond(repoCond) | ||||
| 	milestoneStats, err := models.GetMilestonesStatsByRepoCondAndKw(repoCond, keyword) | ||||
| 	if err != nil { | ||||
| 		ctx.ServerError("GetMilestoneStats", err) | ||||
| 		return | ||||
| @ -287,7 +288,7 @@ func Milestones(ctx *context.Context) { | ||||
| 	if len(repoIDs) == 0 { | ||||
| 		totalMilestoneStats = milestoneStats | ||||
| 	} else { | ||||
| 		totalMilestoneStats, err = models.GetMilestonesStatsByRepoCond(userRepoCond) | ||||
| 		totalMilestoneStats, err = models.GetMilestonesStatsByRepoCondAndKw(userRepoCond, keyword) | ||||
| 		if err != nil { | ||||
| 			ctx.ServerError("GetMilestoneStats", err) | ||||
| 			return | ||||
| @ -310,12 +311,14 @@ func Milestones(ctx *context.Context) { | ||||
| 	ctx.Data["Counts"] = counts | ||||
| 	ctx.Data["MilestoneStats"] = milestoneStats | ||||
| 	ctx.Data["SortType"] = sortType | ||||
| 	ctx.Data["Keyword"] = keyword | ||||
| 	if milestoneStats.Total() != totalMilestoneStats.Total() { | ||||
| 		ctx.Data["RepoIDs"] = repoIDs | ||||
| 	} | ||||
| 	ctx.Data["IsShowClosed"] = isShowClosed | ||||
| 
 | ||||
| 	pager := context.NewPagination(pagerCount, setting.UI.IssuePagingNum, page, 5) | ||||
| 	pager.AddParam(ctx, "q", "Keyword") | ||||
| 	pager.AddParam(ctx, "repos", "RepoIDs") | ||||
| 	pager.AddParam(ctx, "sort", "SortType") | ||||
| 	pager.AddParam(ctx, "state", "State") | ||||
|  | ||||
| @ -12,34 +12,52 @@ | ||||
| 		</div> | ||||
| 		<div class="ui divider"></div> | ||||
| 		{{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"> | ||||
| 		<!-- 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}}">{{.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}}">{{.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}}">{{.i18n.Tr "repo.milestones.filter_sort.least_complete"}}</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> | ||||
| 					<a class="{{if eq .SortType "mostissues"}}active{{end}} item" href="{{$.Link}}?sort=mostissues&state={{$.State}}">{{.i18n.Tr "repo.milestones.filter_sort.most_issues"}}</a> | ||||
| 					<a class="{{if eq .SortType "leastissues"}}active{{end}} item" href="{{$.Link}}?sort=leastissues&state={{$.State}}">{{.i18n.Tr "repo.milestones.filter_sort.least_issues"}}</a> | ||||
| 		<div class="ui three column stackable grid"> | ||||
| 		  <div class="column"> | ||||
| 				<div class="ui compact tiny menu"> | ||||
| 					<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/milestones?state=open&q={{$.Keyword}}"> | ||||
| 						{{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&q={{$.Keyword}}"> | ||||
| 						{{svg "octicon-milestone" 16 "mr-3"}} | ||||
| 						{{.i18n.Tr "repo.milestones.close_tab" .ClosedCount}} | ||||
| 					</a> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 
 | ||||
| 			<!-- 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> | ||||
| 
 | ||||
| 		<!-- milestone list --> | ||||
| 		<div class="milestone list"> | ||||
| 			{{range .Milestones}} | ||||
| 				<li class="item"> | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
| 		<div class="ui stackable grid"> | ||||
| 			<div class="four wide column"> | ||||
| 				<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"}} | ||||
| 						<strong class="ui right">{{.Total}}</strong> | ||||
| 					</a> | ||||
| @ -25,7 +25,7 @@ | ||||
| 										{{$Repo.ID}}%2C | ||||
| 									{{end}} | ||||
| 								{{end}} | ||||
| 								]&sort={{$.SortType}}&state={{$.State}}" title="{{.FullName}}"> | ||||
| 								]&sort={{$.SortType}}&state={{$.State}}&q={{$.Keyword}}" title="{{.FullName}}"> | ||||
| 								<span class="text truncate">{{$Repo.FullName}}</span> | ||||
| 								<div class="ui {{if $.IsShowClosed}}red{{else}}green{{end}} label">{{index $.Counts $Repo.ID}}</div> | ||||
| 							</a> | ||||
| @ -34,34 +34,49 @@ | ||||
| 				</div> | ||||
| 			</div> | ||||
| 			<div class="twelve wide column content"> | ||||
| 				<div class="ui compact tiny menu"> | ||||
| 					<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state=open"> | ||||
| 						{{svg "octicon-issue-opened" 16 "mr-3"}} | ||||
| 						{{.i18n.Tr "repo.milestones.open_tab" .MilestoneStats.OpenCount}} | ||||
| 					</a> | ||||
| 					<a class="item{{if .IsShowClosed}} active{{end}}" href="{{.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state=closed"> | ||||
| 						{{svg "octicon-issue-closed" 16 "mr-3"}} | ||||
| 						{{.i18n.Tr "repo.milestones.close_tab" .MilestoneStats.ClosedCount}} | ||||
| 					</a> | ||||
| 				</div> | ||||
| 				<div class="ui right floated secondary filter menu"> | ||||
| 					<!-- 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 class="ui three column stackable grid"> | ||||
| 					<div class="column"> | ||||
| 						<div class="ui compact tiny menu"> | ||||
| 							<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state=open&q={{$.Keyword}}"> | ||||
| 								{{svg "octicon-issue-opened" 16 "mr-3"}} | ||||
| 								{{.i18n.Tr "repo.milestones.open_tab" .MilestoneStats.OpenCount}} | ||||
| 							</a> | ||||
| 							<a class="item{{if .IsShowClosed}} active{{end}}" href="{{.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state=closed&q={{$.Keyword}}"> | ||||
| 								{{svg "octicon-issue-closed" 16 "mr-3"}} | ||||
| 								{{.i18n.Tr "repo.milestones.close_tab" .MilestoneStats.ClosedCount}} | ||||
| 							</a> | ||||
| 						</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"> | ||||
|                     {{range .Milestones}} | ||||
|                         <li class="item"> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Roger Luo
						Roger Luo