able sort issues

This commit is contained in:
Unknwon 2015-08-15 12:07:08 +08:00
parent 4ce003dc15
commit a52324a5f9
8 changed files with 66 additions and 95 deletions

View file

@ -400,6 +400,13 @@ issues.filter_type.all_issues = All issues
issues.filter_type.assigned_to_you = Assigned to you issues.filter_type.assigned_to_you = Assigned to you
issues.filter_type.created_by_you = Created by you issues.filter_type.created_by_you = Created by you
issues.filter_type.mentioning_you = Mentioning you issues.filter_type.mentioning_you = Mentioning you
issues.filter_sort = Sort
issues.filter_sort.latest = Latest
issues.filter_sort.oldest = Oldest
issues.filter_sort.recentupdate = Recent updated
issues.filter_sort.leastupdate = Least updated
issues.filter_sort.mostcomment = Most comments
issues.filter_sort.leastcomment = Least comments
issues.opened_by = opened %[1]s by <a href="/%[2]s">%[2]s</a> issues.opened_by = opened %[1]s by <a href="/%[2]s">%[2]s</a>
issues.opened_by_fake = opened %[1]s by %[2]s issues.opened_by_fake = opened %[1]s by %[2]s
issues.previous = Previous issues.previous = Previous

View file

@ -1,6 +1,6 @@
{ {
"CodeKitInfo": "This is a CodeKit 2.x project configuration file. It is designed to sync project settings across multiple machines. MODIFYING THE CONTENTS OF THIS FILE IS A POOR LIFE DECISION. If you do so, you will likely cause CodeKit to crash. This file is not useful unless accompanied by the project that created it in CodeKit 2. This file is not backwards-compatible with CodeKit 1.x. For more information, see: http:\/\/incident57.com\/codekit", "CodeKitInfo": "This is a CodeKit 2.x project configuration file. It is designed to sync project settings across multiple machines. MODIFYING THE CONTENTS OF THIS FILE IS A POOR LIFE DECISION. If you do so, you will likely cause CodeKit to crash. This file is not useful unless accompanied by the project that created it in CodeKit 2. This file is not backwards-compatible with CodeKit 1.x. For more information, see: http:\/\/incident57.com\/codekit",
"creatorBuild": "19033", "creatorBuild": "19051",
"files": { "files": {
"\/CONTRIBUTING.md": { "\/CONTRIBUTING.md": {
"criticStyle": 0, "criticStyle": 0,
@ -1635,10 +1635,6 @@
} }
}, },
"jsLintFlags2": { "jsLintFlags2": {
"ass": {
"active": 0,
"flagValue": -1
},
"bitwise": { "bitwise": {
"active": 0, "active": 0,
"flagValue": -1 "flagValue": -1
@ -1647,15 +1643,7 @@
"active": 1, "active": 1,
"flagValue": -1 "flagValue": -1
}, },
"closure": { "couch": {
"active": 0,
"flagValue": -1
},
"continue": {
"active": 0,
"flagValue": -1
},
"debug": {
"active": 0, "active": 0,
"flagValue": -1 "flagValue": -1
}, },
@ -1663,75 +1651,27 @@
"active": 0, "active": 0,
"flagValue": -1 "flagValue": -1
}, },
"eqeq": { "es6": {
"active": 0, "active": 0,
"flagValue": -1 "flagValue": -1
}, },
"evil": { "eval": {
"active": 1,
"flagValue": -1
},
"forin": {
"active": 0, "active": 0,
"flagValue": -1 "flagValue": -1
}, },
"indent": { "for": {
"active": 0, "active": 0,
"flagValue": 4 "flagValue": -1
}, },
"maxlen": { "maxlen": {
"active": 0, "active": 0,
"flagValue": 150 "flagValue": 150
}, },
"newcap": {
"active": 0,
"flagValue": -1
},
"node": { "node": {
"active": 0, "active": 0,
"flagValue": -1 "flagValue": -1
}, },
"nomen": { "this": {
"active": 0,
"flagValue": -1
},
"plusplus": {
"active": 0,
"flagValue": -1
},
"properties": {
"active": 0,
"flagValue": -1
},
"regexp": {
"active": 0,
"flagValue": -1
},
"rhino": {
"active": 0,
"flagValue": -1
},
"sloppy": {
"active": 0,
"flagValue": -1
},
"stupid": {
"active": 0,
"flagValue": -1
},
"sub": {
"active": 0,
"flagValue": -1
},
"todo": {
"active": 0,
"flagValue": -1
},
"unparam": {
"active": 0,
"flagValue": -1
},
"vars": {
"active": 0, "active": 0,
"flagValue": -1 "flagValue": -1
}, },

View file

@ -639,7 +639,7 @@ func parseCountResult(results []map[string][]byte) int64 {
} }
// GetIssueStats returns issue statistic information by given conditions. // GetIssueStats returns issue statistic information by given conditions.
func GetIssueStats(repoID, uid, labelID, milestoneID int64, isShowClosed bool, filterMode int) *IssueStats { func GetIssueStats(repoID, uid, labelID, milestoneID, assigneeID int64, isShowClosed bool, filterMode int) *IssueStats {
stats := &IssueStats{} stats := &IssueStats{}
// issue := new(Issue) // issue := new(Issue)
@ -652,20 +652,16 @@ func GetIssueStats(repoID, uid, labelID, milestoneID int64, isShowClosed bool, f
if milestoneID > 0 { if milestoneID > 0 {
baseCond += " AND issue.milestone_id=" + com.ToStr(milestoneID) baseCond += " AND issue.milestone_id=" + com.ToStr(milestoneID)
} }
if assigneeID > 0 {
baseCond += " AND assignee_id=" + com.ToStr(assigneeID)
}
switch filterMode { switch filterMode {
case FM_ALL: case FM_ALL, FM_ASSIGN:
resutls, _ := x.Query(queryStr+baseCond, repoID, false) resutls, _ := x.Query(queryStr+baseCond, repoID, false)
stats.OpenCount = parseCountResult(resutls) stats.OpenCount = parseCountResult(resutls)
resutls, _ = x.Query(queryStr+baseCond, repoID, true) resutls, _ = x.Query(queryStr+baseCond, repoID, true)
stats.ClosedCount = parseCountResult(resutls) stats.ClosedCount = parseCountResult(resutls)
case FM_ASSIGN:
baseCond += " AND assignee_id=?"
resutls, _ := x.Query(queryStr+baseCond, repoID, false, uid)
stats.OpenCount = parseCountResult(resutls)
resutls, _ = x.Query(queryStr+baseCond, repoID, true, uid)
stats.ClosedCount = parseCountResult(resutls)
case FM_CREATE: case FM_CREATE:
baseCond += " AND poster_id=?" baseCond += " AND poster_id=?"
resutls, _ := x.Query(queryStr+baseCond, repoID, false, uid) resutls, _ := x.Query(queryStr+baseCond, repoID, false, uid)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -73,6 +73,10 @@
right: 0!important; right: 0!important;
left: auto!important; left: auto!important;
} }
.dropdown.item {
margin: 1px;
padding-right: 0;
}
} }
.page.buttons { .page.buttons {

View file

@ -59,6 +59,7 @@ func Issues(ctx *middleware.Context) {
ctx.Data["PageIsIssueList"] = true ctx.Data["PageIsIssueList"] = true
viewType := ctx.Query("type") viewType := ctx.Query("type")
sortType := ctx.Query("sort")
types := []string{"assigned", "created_by", "mentioned"} types := []string{"assigned", "created_by", "mentioned"}
if !com.IsSliceContainsStr(types, viewType) { if !com.IsSliceContainsStr(types, viewType) {
viewType = "all" viewType = "all"
@ -71,7 +72,10 @@ func Issues(ctx *middleware.Context) {
return return
} }
var assigneeID, posterID int64 var (
assigneeID = ctx.QueryInt64("assignee")
posterID int64
)
filterMode := models.FM_ALL filterMode := models.FM_ALL
switch viewType { switch viewType {
case "assigned": case "assigned":
@ -92,9 +96,8 @@ func Issues(ctx *middleware.Context) {
repo := ctx.Repo.Repository repo := ctx.Repo.Repository
selectLabels := ctx.Query("labels") selectLabels := ctx.Query("labels")
milestoneID := ctx.QueryInt64("milestone") milestoneID := ctx.QueryInt64("milestone")
assigneeID = ctx.QueryInt64("assignee")
isShowClosed := ctx.Query("state") == "closed" isShowClosed := ctx.Query("state") == "closed"
issueStats := models.GetIssueStats(repo.ID, uid, com.StrTo(selectLabels).MustInt64(), milestoneID, isShowClosed, filterMode) issueStats := models.GetIssueStats(repo.ID, uid, com.StrTo(selectLabels).MustInt64(), milestoneID, assigneeID, isShowClosed, filterMode)
page := ctx.QueryInt("page") page := ctx.QueryInt("page")
if page <= 1 { if page <= 1 {
@ -111,7 +114,7 @@ func Issues(ctx *middleware.Context) {
// Get issues. // Get issues.
issues, err := models.Issues(uid, assigneeID, repo.ID, posterID, milestoneID, issues, err := models.Issues(uid, assigneeID, repo.ID, posterID, milestoneID,
page, isShowClosed, filterMode == models.FM_MENTION, selectLabels, ctx.Query("sortType")) page, isShowClosed, filterMode == models.FM_MENTION, selectLabels, sortType)
if err != nil { if err != nil {
ctx.Handle(500, "Issues: %v", err) ctx.Handle(500, "Issues: %v", err)
return return
@ -168,6 +171,7 @@ func Issues(ctx *middleware.Context) {
ctx.Data["IssueStats"] = issueStats ctx.Data["IssueStats"] = issueStats
ctx.Data["SelectLabels"] = com.StrTo(selectLabels).MustInt64() ctx.Data["SelectLabels"] = com.StrTo(selectLabels).MustInt64()
ctx.Data["ViewType"] = viewType ctx.Data["ViewType"] = viewType
ctx.Data["SortType"] = sortType
ctx.Data["MilestoneID"] = milestoneID ctx.Data["MilestoneID"] = milestoneID
ctx.Data["AssigneeID"] = assigneeID ctx.Data["AssigneeID"] = assigneeID
ctx.Data["IsShowClosed"] = isShowClosed ctx.Data["IsShowClosed"] = isShowClosed

View file

@ -10,11 +10,11 @@
</div> </div>
<div class="ui divider"></div> <div class="ui divider"></div>
<div class="ui tiny buttons"> <div class="ui tiny buttons">
<a class="ui green basic button {{if not .IsShowClosed}}active{{end}}" href="{{.RepoLink}}/issues?type={{$.ViewType}}&state=open&labels={{.SelectLabels}}&milestone={{.MilestoneID}}&assignee={{.AssigneeID}}"> <a class="ui green basic button {{if not .IsShowClosed}}active{{end}}" href="{{.RepoLink}}/issues?type={{$.ViewType}}&sort={{$.SortType}}&state=open&labels={{.SelectLabels}}&milestone={{.MilestoneID}}&assignee={{.AssigneeID}}">
<i class="octicon octicon-issue-opened"></i> <i class="octicon octicon-issue-opened"></i>
{{.i18n.Tr "repo.issues.open_tab" .IssueStats.OpenCount}} {{.i18n.Tr "repo.issues.open_tab" .IssueStats.OpenCount}}
</a> </a>
<a class="ui red basic button {{if .IsShowClosed}}active{{end}}" href="{{.RepoLink}}/issues?type={{.ViewType}}&state=closed&labels={{.SelectLabels}}&milestone={{.MilestoneID}}&assignee={{.AssigneeID}}"> <a class="ui red basic button {{if .IsShowClosed}}active{{end}}" href="{{.RepoLink}}/issues?type={{.ViewType}}&sort={{$.SortType}}&state=closed&labels={{.SelectLabels}}&milestone={{.MilestoneID}}&assignee={{.AssigneeID}}">
<i class="octicon octicon-issue-closed"></i> <i class="octicon octicon-issue-closed"></i>
{{.i18n.Tr "repo.issues.close_tab" .IssueStats.ClosedCount}} {{.i18n.Tr "repo.issues.close_tab" .IssueStats.ClosedCount}}
</a> </a>
@ -27,9 +27,9 @@
<i class="dropdown icon"></i> <i class="dropdown icon"></i>
</span> </span>
<div class="menu"> <div class="menu">
<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_label_no_select"}}</a> <a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_label_no_select"}}</a>
{{range .Labels}} {{range .Labels}}
<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}"><span class="octicon {{if eq $.SelectLabels .ID}}octicon-check{{end}}"></span><span class="label color" style="background-color: {{.Color}}"></span> {{.Name}}</a> <a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.ID}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}"><span class="octicon {{if eq $.SelectLabels .ID}}octicon-check{{end}}"></span><span class="label color" style="background-color: {{.Color}}"></span> {{.Name}}</a>
{{end}} {{end}}
</div> </div>
</div> </div>
@ -41,34 +41,54 @@
<i class="dropdown icon"></i> <i class="dropdown icon"></i>
</span> </span>
<div class="menu"> <div class="menu">
<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_milestone_no_select"}}</a> <a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_milestone_no_select"}}</a>
{{range .Milestones}} {{range .Milestones}}
<a class="{{if eq $.MilestoneID .ID}}active selected{{end}} item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{.ID}}&assignee={{$.AssigneeID}}">{{.Name}}</a> <a class="{{if eq $.MilestoneID .ID}}active selected{{end}} item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{.ID}}&assignee={{$.AssigneeID}}">{{.Name}}</a>
{{end}} {{end}}
</div> </div>
</div> </div>
<!-- Assignee -->
<div class="ui {{if not .Assignees}}disabled{{end}} dropdown jump item"> <div class="ui {{if not .Assignees}}disabled{{end}} dropdown jump item">
<span class="text"> <span class="text">
{{.i18n.Tr "repo.issues.filter_assignee"}} {{.i18n.Tr "repo.issues.filter_assignee"}}
<i class="dropdown icon"></i> <i class="dropdown icon"></i>
</span> </span>
<div class="menu"> <div class="menu">
<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}">{{.i18n.Tr "repo.issues.filter_assginee_no_select"}}</a> <a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}">{{.i18n.Tr "repo.issues.filter_assginee_no_select"}}</a>
{{range .Assignees}} {{range .Assignees}}
<a class="{{if eq $.AssigneeID .Id}}active selected{{end}} item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{.Id}}"><img src="{{.AvatarLink}}"> {{.Name}}</a> <a class="{{if eq $.AssigneeID .Id}}active selected{{end}} item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{.Id}}"><img src="{{.AvatarLink}}"> {{.Name}}</a>
{{end}} {{end}}
</div> </div>
</div> </div>
<!-- Type -->
<div class="ui dropdown type jump item"> <div class="ui dropdown type jump item">
<span class="text"> <span class="text">
{{.i18n.Tr "repo.issues.filter_type"}} {{.i18n.Tr "repo.issues.filter_type"}}
<i class="dropdown icon"></i> <i class="dropdown icon"></i>
</span> </span>
<div class="menu"> <div class="menu">
<a class="{{if eq .ViewType "all"}}active{{end}} item" href="{{$.RepoLink}}/issues?type=all&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.all_issues"}}</a> <a class="{{if eq .ViewType "all"}}active{{end}} item" href="{{$.RepoLink}}/issues?type=all&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.all_issues"}}</a>
<a class="{{if eq .ViewType "assigned"}}active{{end}} item" href="{{$.RepoLink}}/issues?type=assigned&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}">{{.i18n.Tr "repo.issues.filter_type.assigned_to_you"}}</a> <a class="{{if eq .ViewType "assigned"}}active{{end}} item" href="{{$.RepoLink}}/issues?type=assigned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}">{{.i18n.Tr "repo.issues.filter_type.assigned_to_you"}}</a>
<a class="{{if eq .ViewType "created_by"}}active{{end}} item" href="{{$.RepoLink}}/issues?type=created_by&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.created_by_you"}}</a> <a class="{{if eq .ViewType "created_by"}}active{{end}} item" href="{{$.RepoLink}}/issues?type=created_by&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.created_by_you"}}</a>
<a class="{{if eq .ViewType "mentioned"}}active{{end}} item" href="{{$.RepoLink}}/issues?type=mentioned&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.mentioning_you"}}</a> <a class="{{if eq .ViewType "mentioned"}}active{{end}} item" href="{{$.RepoLink}}/issues?type=mentioned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.mentioning_you"}}</a>
</div>
</div>
<!-- Sort -->
<div class="ui dropdown type jump item">
<span class="text">
{{.i18n.Tr "repo.issues.filter_sort"}}
<i class="dropdown icon"></i>
</span>
<div class="menu">
<a class="{{if or (eq .SortType "latest") (not .SortType)}}active{{end}} item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&sort=latest&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a>
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&sort=oldest&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&sort=recentupdate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a>
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&sort=leastupdate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a>
<a class="{{if eq .SortType "mostcomment"}}active{{end}} item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&sort=mostcomment&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_sort.mostcomment"}}</a>
<a class="{{if eq .SortType "leastcomment"}}active{{end}} item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&sort=leastcomment&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_sort.leastcomment"}}</a>
</div> </div>
</div> </div>
</div> </div>