Преглед на файлове

new issue and label page

Unknwon преди 9 години
родител
ревизия
1ba837a055
променени са 11 файла, в които са добавени 125 реда и са изтрити 117 реда
  1. 4 0
      conf/app.ini
  2. 1 0
      conf/locale/locale_en-US.ini
  3. 1 1
      gogs.go
  4. 50 59
      models/issue.go
  5. 0 0
      modules/bindata/bindata.go
  6. 8 3
      modules/setting/setting.go
  7. 0 0
      public/css/gogs.min.css
  8. 14 2
      public/less/_repository.less
  9. 29 38
      routers/repo/issue.go
  10. 1 1
      templates/.VERSION
  11. 17 13
      templates/repo/issue/list.tmpl

+ 4 - 0
conf/app.ini

@@ -12,6 +12,10 @@ RUN_MODE = dev
 ROOT =
 SCRIPT_TYPE = bash
 
+[ui]
+; Number of issues that are showed in one page
+ISSUE_PAGING_NUM = 10
+
 [server]
 PROTOCOL = http
 DOMAIN = localhost

+ 1 - 0
conf/locale/locale_en-US.ini

@@ -370,6 +370,7 @@ issues.new_label_placeholder = Label name...
 issues.open_tab = %d Open
 issues.close_tab = %d Closed
 issues.filter_label = Label
+issues.filter_label_no_select = No selected label
 issues.filter_milestone = Milestone
 issues.filter_assignee = Assignee
 issues.filter_type = Type

+ 1 - 1
gogs.go

@@ -17,7 +17,7 @@ import (
 	"github.com/gogits/gogs/modules/setting"
 )
 
-const APP_VER = "0.6.2.0724 Beta"
+const APP_VER = "0.6.2.0725 Beta"
 
 func init() {
 	runtime.GOMAXPROCS(runtime.NumCPU())

+ 50 - 59
models/issue.go

@@ -14,7 +14,6 @@ import (
 	"time"
 
 	"github.com/Unknwon/com"
-	"github.com/go-xorm/xorm"
 
 	"github.com/gogits/gogs/modules/log"
 	"github.com/gogits/gogs/modules/setting"
@@ -73,7 +72,7 @@ func (i *Issue) GetLabels() error {
 	strIds := strings.Split(strings.TrimSuffix(i.LabelIds[1:], "|"), "|$")
 	i.Labels = make([]*Label, 0, len(strIds))
 	for _, strId := range strIds {
-		id, _ := com.StrTo(strId).Int64()
+		id := com.StrTo(strId).MustInt64()
 		if id > 0 {
 			l, err := GetLabelById(id)
 			if err != nil {
@@ -186,29 +185,29 @@ func GetIssueById(id int64) (*Issue, error) {
 }
 
 // GetIssues returns a list of issues by given conditions.
-func GetIssues(uid, rid, pid, mid int64, page int, isClosed bool, labelIds, sortType string) ([]Issue, error) {
+func GetIssues(uid, assigneeID, repoID, posterID, milestoneID int64, page int, isClosed, isMention bool, labelIds, sortType string) ([]Issue, error) {
 	sess := x.Limit(setting.IssuePagingNum, (page-1)*setting.IssuePagingNum)
 
-	if rid > 0 {
-		sess.Where("repo_id=?", rid).And("is_closed=?", isClosed)
+	if repoID > 0 {
+		sess.Where("issue.repo_id=?", repoID).And("issue.is_closed=?", isClosed)
 	} else {
-		sess.Where("is_closed=?", isClosed)
+		sess.Where("issue.is_closed=?", isClosed)
 	}
 
-	if uid > 0 {
-		sess.And("assignee_id=?", uid)
-	} else if pid > 0 {
-		sess.And("poster_id=?", pid)
+	if assigneeID > 0 {
+		sess.And("issue.assignee_id=?", assigneeID)
+	} else if posterID > 0 {
+		sess.And("issue.poster_id=?", posterID)
 	}
 
-	if mid > 0 {
-		sess.And("milestone_id=?", mid)
+	if milestoneID > 0 {
+		sess.And("issue.milestone_id=?", milestoneID)
 	}
 
 	if len(labelIds) > 0 {
 		for _, label := range strings.Split(labelIds, ",") {
 			if com.StrTo(label).MustInt() > 0 {
-				sess.And("label_ids like ?", "'%$"+label+"|%'")
+				sess.And("label_ids like ?", "%$"+label+"|%")
 			}
 		}
 	}
@@ -230,6 +229,14 @@ func GetIssues(uid, rid, pid, mid int64, page int, isClosed bool, labelIds, sort
 		sess.Desc("created")
 	}
 
+	if isMention {
+		queryStr := "issue.id == issue_user.issue_id AND issue_user.is_mentioned=1"
+		if uid > 0 {
+			queryStr += " AND issue_user.uid = " + com.ToStr(uid)
+		}
+		sess.Join("INNER", "issue_user", queryStr)
+	}
+
 	var issues []Issue
 	return issues, sess.Find(&issues)
 }
@@ -394,53 +401,42 @@ type IssueStats struct {
 
 // Filter modes.
 const (
-	FM_ASSIGN = iota + 1
+	FM_ALL = iota
+	FM_ASSIGN
 	FM_CREATE
 	FM_MENTION
 )
 
 // GetIssueStats returns issue statistic information by given conditions.
-func GetIssueStats(rid, uid int64, isShowClosed bool, filterMode int) *IssueStats {
+func GetIssueStats(repoID, uid, labelID int64, isShowClosed bool, filterMode int) *IssueStats {
 	stats := &IssueStats{}
 	issue := new(Issue)
-	tmpSess := &xorm.Session{}
-
-	sess := x.Where("repo_id=?", rid)
-	*tmpSess = *sess
-	stats.OpenCount, _ = tmpSess.And("is_closed=?", false).Count(issue)
-	*tmpSess = *sess
-	stats.ClosedCount, _ = tmpSess.And("is_closed=?", true).Count(issue)
-	if isShowClosed {
-		stats.AllCount = stats.ClosedCount
-	} else {
-		stats.AllCount = stats.OpenCount
-	}
-
-	if filterMode != FM_MENTION {
-		sess = x.Where("repo_id=?", rid)
-		switch filterMode {
-		case FM_ASSIGN:
-			sess.And("assignee_id=?", uid)
-		case FM_CREATE:
-			sess.And("poster_id=?", uid)
-		default:
-			goto nofilter
-		}
-		*tmpSess = *sess
-		stats.OpenCount, _ = tmpSess.And("is_closed=?", false).Count(issue)
-		*tmpSess = *sess
-		stats.ClosedCount, _ = tmpSess.And("is_closed=?", true).Count(issue)
-	} else {
-		sess := x.Where("repo_id=?", rid).And("uid=?", uid).And("is_mentioned=?", true)
-		*tmpSess = *sess
-		stats.OpenCount, _ = tmpSess.And("is_closed=?", false).Count(new(IssueUser))
-		*tmpSess = *sess
-		stats.ClosedCount, _ = tmpSess.And("is_closed=?", true).Count(new(IssueUser))
-	}
-nofilter:
-	stats.AssignCount, _ = x.Where("repo_id=?", rid).And("is_closed=?", isShowClosed).And("assignee_id=?", uid).Count(issue)
-	stats.CreateCount, _ = x.Where("repo_id=?", rid).And("is_closed=?", isShowClosed).And("poster_id=?", uid).Count(issue)
-	stats.MentionCount, _ = x.Where("repo_id=?", rid).And("uid=?", uid).And("is_closed=?", isShowClosed).And("is_mentioned=?", true).Count(new(IssueUser))
+
+	queryStr := "repo_id=? AND is_closed=?"
+	switch filterMode {
+	case FM_ALL:
+		stats.OpenCount, _ = x.Where(queryStr, repoID, false).Count(issue)
+		stats.ClosedCount, _ = x.Where(queryStr, repoID, true).Count(issue)
+		return stats
+
+	case FM_ASSIGN:
+		queryStr += " AND assignee_id=?"
+		stats.OpenCount, _ = x.Where(queryStr, repoID, false, uid).Count(issue)
+		stats.ClosedCount, _ = x.Where(queryStr, repoID, true, uid).Count(issue)
+		return stats
+
+	case FM_CREATE:
+		queryStr += " AND poster_id=?"
+		stats.OpenCount, _ = x.Where(queryStr, repoID, false, uid).Count(issue)
+		stats.ClosedCount, _ = x.Where(queryStr, repoID, true, uid).Count(issue)
+		return stats
+
+	case FM_MENTION:
+		queryStr += " AND uid=? AND is_mentioned=?"
+		stats.OpenCount, _ = x.Where(queryStr, repoID, false, uid, true).Count(new(IssueUser))
+		stats.ClosedCount, _ = x.Where(queryStr, repoID, true, uid, true).Count(new(IssueUser))
+		return stats
+	}
 	return stats
 }
 
@@ -894,7 +890,7 @@ type Comment struct {
 // CreateComment creates comment of issue or commit.
 func CreateComment(userId, repoId, issueId, commitId, line int64, cmtType CommentType, content string, attachments []int64) (*Comment, error) {
 	sess := x.NewSession()
-	defer sess.Close()
+	defer sessionRelease(sess)
 	if err := sess.Begin(); err != nil {
 		return nil, err
 	}
@@ -903,7 +899,6 @@ func CreateComment(userId, repoId, issueId, commitId, line int64, cmtType Commen
 		CommitId: commitId, Line: line, Content: content}
 
 	if _, err := sess.Insert(comment); err != nil {
-		sess.Rollback()
 		return nil, err
 	}
 
@@ -912,7 +907,6 @@ func CreateComment(userId, repoId, issueId, commitId, line int64, cmtType Commen
 	case COMMENT_TYPE_COMMENT:
 		rawSql := "UPDATE `issue` SET num_comments = num_comments + 1 WHERE id = ?"
 		if _, err := sess.Exec(rawSql, issueId); err != nil {
-			sess.Rollback()
 			return nil, err
 		}
 
@@ -926,20 +920,17 @@ func CreateComment(userId, repoId, issueId, commitId, line int64, cmtType Commen
 			}
 
 			if _, err := sess.Exec(rawSql, comment.Id, strings.Join(astrs, ",")); err != nil {
-				sess.Rollback()
 				return nil, err
 			}
 		}
 	case COMMENT_TYPE_REOPEN:
 		rawSql := "UPDATE `repository` SET num_closed_issues = num_closed_issues - 1 WHERE id = ?"
 		if _, err := sess.Exec(rawSql, repoId); err != nil {
-			sess.Rollback()
 			return nil, err
 		}
 	case COMMENT_TYPE_CLOSE:
 		rawSql := "UPDATE `repository` SET num_closed_issues = num_closed_issues + 1 WHERE id = ?"
 		if _, err := sess.Exec(rawSql, repoId); err != nil {
-			sess.Rollback()
 			return nil, err
 		}
 	}

Файловите разлики са ограничени, защото са твърде много
+ 0 - 0
modules/bindata/bindata.go


+ 8 - 3
modules/setting/setting.go

@@ -82,9 +82,11 @@ var (
 	}
 
 	// Repository settings.
-	RepoRootPath   string
-	ScriptType     string
-	IssuePagingNum int = 10
+	RepoRootPath string
+	ScriptType   string
+
+	// UI settings.
+	IssuePagingNum int
 
 	// Picture settings.
 	PictureService   string
@@ -311,6 +313,9 @@ func NewConfigContext() {
 	}
 	ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash")
 
+	// UI settings.
+	IssuePagingNum = Cfg.Section("ui").Key("ISSUE_PAGING_NUM").MustInt(10)
+
 	sec = Cfg.Section("picture")
 	PictureService = sec.Key("SERVICE").In("server", []string{"server"})
 	AvatarUploadPath = sec.Key("AVATAR_UPLOAD_PATH").MustString("data/avatars")

Файловите разлики са ограничени, защото са твърде много
+ 0 - 0
public/css/gogs.min.css


+ 14 - 2
public/less/_repository.less

@@ -78,8 +78,20 @@
 			}
 		}
 	}
-	.filter.menu .label.color {
-		padding: 0 8px;
+	.filter.menu {
+		.label.color {
+			margin-left: 17px;
+			padding: 0 8px;
+		}
+		.octicon {
+			float: left;
+			margin-left: -5px;
+			margin-right: -7px;
+		}
+		.menu {
+			max-height: 300px;
+			overflow-x: auto;
+		}
 	}
 	.type.item .menu {
 		  right: 0!important;

+ 29 - 38
routers/repo/issue.go

@@ -74,32 +74,26 @@ func Issues(ctx *middleware.Context) {
 		return
 	}
 
-	var assigneeId, posterId int64
-	var filterMode int
+	var assigneeID, posterID int64
+	filterMode := models.FM_ALL
 	switch viewType {
 	case "assigned":
-		assigneeId = ctx.User.Id
+		assigneeID = ctx.User.Id
 		filterMode = models.FM_ASSIGN
 	case "created_by":
-		posterId = ctx.User.Id
+		posterID = ctx.User.Id
 		filterMode = models.FM_CREATE
 	case "mentioned":
 		filterMode = models.FM_MENTION
 	}
 
-	repo := ctx.Repo.Repository
-
-	var mid int64
-	midx := ctx.QueryInt64("milestone")
-	if midx > 0 {
-		mile, err := models.GetMilestoneByIndex(repo.Id, midx)
-		if err != nil {
-			ctx.Handle(500, "GetMilestoneByIndex: %v", err)
-			return
-		}
-		mid = mile.Id
+	var uid int64 = -1
+	if ctx.IsSigned {
+		uid = ctx.User.Id
 	}
 
+	repo := ctx.Repo.Repository
+	milestoneID := ctx.QueryInt64("milestone")
 	page := ctx.QueryInt("page")
 	if page <= 1 {
 		page = 1
@@ -114,15 +108,15 @@ func Issues(ctx *middleware.Context) {
 	selectLabels := ctx.Query("labels")
 
 	// Get issues.
-	issues, err := models.GetIssues(assigneeId, repo.Id, posterId, mid, page,
-		isShowClosed, selectLabels, ctx.Query("sortType"))
+	issues, err := models.GetIssues(uid, assigneeID, repo.Id, posterID, milestoneID,
+		page, isShowClosed, filterMode == models.FM_MENTION, selectLabels, ctx.Query("sortType"))
 	if err != nil {
 		ctx.Handle(500, "GetIssues: %v", err)
 		return
 	}
 
 	// Get issue-user pairs.
-	pairs, err := models.GetIssueUserPairs(repo.Id, posterId, isShowClosed)
+	pairs, err := models.GetIssueUserPairs(repo.Id, posterID, isShowClosed)
 	if err != nil {
 		ctx.Handle(500, "GetIssueUserPairs: %v", err)
 		return
@@ -130,36 +124,31 @@ func Issues(ctx *middleware.Context) {
 
 	// Get posters.
 	for i := range issues {
+		if err = issues[i].GetPoster(); err != nil {
+			ctx.Handle(500, "GetPoster", fmt.Errorf("[#%d]%v", issues[i].ID, err))
+			return
+		}
+
 		if err = issues[i].GetLabels(); err != nil {
 			ctx.Handle(500, "GetLabels", fmt.Errorf("[#%d]%v", issues[i].ID, err))
 			return
 		}
 
-		if ctx.IsSigned {
-			idx := models.PairsContains(pairs, issues[i].ID, ctx.User.Id)
-
-			if filterMode == models.FM_MENTION && (idx == -1 || !pairs[idx].IsMentioned) {
-				continue
-			}
-
-			if idx > -1 {
-				issues[i].IsRead = pairs[idx].IsRead
-			} else {
-				issues[i].IsRead = true
-			}
+		if !ctx.IsSigned {
+			issues[i].IsRead = true
+			continue
 		}
 
-		if err = issues[i].GetPoster(); err != nil {
-			ctx.Handle(500, "GetPoster", fmt.Errorf("[#%d]%v", issues[i].ID, err))
-			return
+		// Check read status.
+		idx := models.PairsContains(pairs, issues[i].ID, ctx.User.Id)
+		if idx > -1 {
+			issues[i].IsRead = pairs[idx].IsRead
+		} else {
+			issues[i].IsRead = true
 		}
 	}
 
-	var uid int64 = -1
-	if ctx.User != nil {
-		uid = ctx.User.Id
-	}
-	issueStats := models.GetIssueStats(repo.Id, uid, isShowClosed, filterMode)
+	issueStats := models.GetIssueStats(repo.Id, uid, com.StrTo(selectLabels).MustInt64(), isShowClosed, filterMode)
 	ctx.Data["IssueStats"] = issueStats
 	ctx.Data["SelectLabels"] = com.StrTo(selectLabels).MustInt64()
 	ctx.Data["ViewType"] = viewType
@@ -169,8 +158,10 @@ func Issues(ctx *middleware.Context) {
 		ctx.Data["State"] = "closed"
 		ctx.Data["ShowCount"] = issueStats.ClosedCount
 	} else {
+		ctx.Data["State"] = "open"
 		ctx.Data["ShowCount"] = issueStats.OpenCount
 	}
+
 	ctx.HTML(200, ISSUES)
 }
 

+ 1 - 1
templates/.VERSION

@@ -1 +1 @@
-0.6.2.0724 Beta
+0.6.2.0725 Beta

+ 17 - 13
templates/repo/issue/list.tmpl

@@ -4,20 +4,18 @@
 	<div class="ui middle page grid body">
 		<div class="navbar">
 			{{template "repo/issue/navbar" .}}
-			{{if .IsRepositoryAdmin}}
 			<div class="ui right floated secondary menu">
 				<a class="ui green button" href="{{$.RepoLink}}/issues/new">{{.i18n.Tr "repo.issues.new"}}</a>
 			</div>
-			{{end}}
 		</div>
 		<div class="ui divider"></div>
 		<div class="ui left">
 			<div class="ui tiny buttons">
-			  <a class="ui green basic button {{if not .IsShowClosed}}active{{end}}" href="{{.RepoLink}}/issues?type={{.ViewType}}">
+			  <a class="ui green basic button {{if not .IsShowClosed}}active{{end}}" href="{{.RepoLink}}/issues?type={{$.ViewType}}&state=open&labels={{.SelectLabels}}">
 			  	<i class="octicon octicon-issue-opened"></i>
 			  	{{.i18n.Tr "repo.issues.open_tab" .IssueStats.OpenCount}}
 			  </a>
-			  <a class="ui red basic button {{if .IsShowClosed}}active{{end}}" href="{{.RepoLink}}/issues?type={{.ViewType}}&state=closed">
+			  <a class="ui red basic button {{if .IsShowClosed}}active{{end}}" href="{{.RepoLink}}/issues?type={{.ViewType}}&state=closed&labels={{.SelectLabels}}">
 			  	<i class="octicon octicon-issue-closed"></i>
 			  	{{.i18n.Tr "repo.issues.close_tab" .IssueStats.ClosedCount}}
 			  </a>
@@ -30,12 +28,13 @@
 					<i class="dropdown icon"></i>
 				</span>
         <div class="menu">
+        	<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}">{{.i18n.Tr "repo.issues.filter_label_no_select"}}</a>
         	{{range .Labels}}
-        	<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}"><span class="label color" style="background-color: {{.Color}}"></span> {{.Name}}</a>
+        	<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}"><span class="octicon {{if eq $.SelectLabels .ID}}octicon-check{{end}}"></span><span class="label color" style="background-color: {{.Color}}"></span> {{.Name}}</a>
           {{end}}
 				</div>
 			</div>
-			<div class="ui {{if not .Milestones}}disabled{{end}} pointing dropdown jump item">
+			<!-- <div class="ui {{if not .Milestones}}disabled{{end}} pointing dropdown jump item">
 				<span class="text">
 					{{.i18n.Tr "repo.issues.filter_milestone"}}
 					<i class="dropdown icon"></i>
@@ -45,8 +44,8 @@
         	<a class="item" href="{{$.RepoLink}}/issues">{{.Name}}</a>
           {{end}}
 				</div>
-			</div>
-			<div class="ui {{if not .Assignees}}disabled{{end}} pointing dropdown jump item">
+			</div> -->
+			<!-- <div class="ui {{if not .Assignees}}disabled{{end}} pointing dropdown jump item">
 				<span class="text">
 					{{.i18n.Tr "repo.issues.filter_assignee"}}
 					<i class="dropdown icon"></i>
@@ -56,17 +55,17 @@
         	<a class="item" href="{{$.RepoLink}}/issues">{{.Name}}</a>
           {{end}}
 				</div>
-			</div>
+			</div> -->
 			<div class="ui pointing dropdown type jump item">
 				<span class="text">
 					{{.i18n.Tr "repo.issues.filter_type"}}
 					<i class="dropdown icon"></i>
 				</span>
         <div class="menu">
-        	<a class="item" href="{{$.RepoLink}}/issues">{{.i18n.Tr "repo.issues.filter_type.all_issues"}}</a>
-        	<a class="item" href="{{$.RepoLink}}/issues">{{.i18n.Tr "repo.issues.filter_type.assigned_to_you"}}</a>
-        	<a class="item" href="{{$.RepoLink}}/issues">{{.i18n.Tr "repo.issues.filter_type.created_by_you"}}</a>
-        	<a class="item" href="{{$.RepoLink}}/issues">{{.i18n.Tr "repo.issues.filter_type.mentioning_you"}}</a>
+        	<a class="{{if eq .ViewType "all"}}active{{end}} item" href="{{$.RepoLink}}/issues?type=all&state={{$.State}}&labels={{.SelectLabels}}">{{.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}}">{{.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}}">{{.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}}">{{.i18n.Tr "repo.issues.filter_type.mentioning_you"}}</a>
 				</div>
 			</div>
 		</div>
@@ -77,6 +76,11 @@
       <li class="item">
       	<div class="ui {{if .IsRead}}black{{else}}green{{end}} label">#{{.Index}}</div>
       	<a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Name}}</a>
+
+      	{{range .Labels}}
+				<a class="ui label" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}" style="background-color: {{.Color}}">{{.Name}}</a>
+      	{{end}}
+
       	{{if .NumComments}}<span class="comment ui right"><i class="octicon octicon-comment"></i> {{.NumComments}}</span>{{end}}
         <p class="desc">{{$.i18n.Tr "repo.issues.opened_by" $timeStr .Poster.Name|Str2html}}</p>
       </li>

Някои файлове не бяха показани, защото твърде много файлове са промени