mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-04 09:44:21 +00:00 
			
		
		
		
	new user dahsboard issues
This commit is contained in:
		@@ -124,6 +124,8 @@ collaborative_repos = Collaborative Repositories
 | 
				
			|||||||
my_orgs = My Organizations
 | 
					my_orgs = My Organizations
 | 
				
			||||||
my_mirrors = My Mirrors
 | 
					my_mirrors = My Mirrors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					issues.in_your_repos = In your repositories
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[explore]
 | 
					[explore]
 | 
				
			||||||
repos = Repositories
 | 
					repos = Repositories
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -275,6 +275,26 @@
 | 
				
			|||||||
		"strictMath": 0,
 | 
							"strictMath": 0,
 | 
				
			||||||
		"strictUnits": 0
 | 
							"strictUnits": 0
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
						"\/public\/less\/_dashboard.less": {
 | 
				
			||||||
 | 
							"allowInsecureImports": 0,
 | 
				
			||||||
 | 
							"createSourceMap": 0,
 | 
				
			||||||
 | 
							"disableJavascript": 0,
 | 
				
			||||||
 | 
							"fileType": 1,
 | 
				
			||||||
 | 
							"ieCompatibility": 1,
 | 
				
			||||||
 | 
							"ignore": 1,
 | 
				
			||||||
 | 
							"ignoreWasSetByUser": 0,
 | 
				
			||||||
 | 
							"inputAbbreviatedPath": "\/public\/less\/_dashboard.less",
 | 
				
			||||||
 | 
							"outputAbbreviatedPath": "\/public\/css\/_dashboard.css",
 | 
				
			||||||
 | 
							"outputPathIsOutsideProject": 0,
 | 
				
			||||||
 | 
							"outputPathIsSetByUser": 0,
 | 
				
			||||||
 | 
							"outputStyle": 0,
 | 
				
			||||||
 | 
							"relativeURLS": 0,
 | 
				
			||||||
 | 
							"shouldRunAutoprefixer": 0,
 | 
				
			||||||
 | 
							"shouldRunBless": 0,
 | 
				
			||||||
 | 
							"strictImports": 0,
 | 
				
			||||||
 | 
							"strictMath": 0,
 | 
				
			||||||
 | 
							"strictUnits": 0
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	"\/public\/less\/_form.less": {
 | 
						"\/public\/less\/_form.less": {
 | 
				
			||||||
		"allowInsecureImports": 0,
 | 
							"allowInsecureImports": 0,
 | 
				
			||||||
		"createSourceMap": 0,
 | 
							"createSourceMap": 0,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -641,9 +641,8 @@ 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, assigneeID int64, isShowClosed bool, filterMode int) *IssueStats {
 | 
					func GetIssueStats(repoID, uid, labelID, milestoneID, assigneeID int64, filterMode int) *IssueStats {
 | 
				
			||||||
	stats := &IssueStats{}
 | 
						stats := &IssueStats{}
 | 
				
			||||||
	// issue := new(Issue)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	queryStr := "SELECT COUNT(*) FROM `issue` "
 | 
						queryStr := "SELECT COUNT(*) FROM `issue` "
 | 
				
			||||||
	if labelID > 0 {
 | 
						if labelID > 0 {
 | 
				
			||||||
@@ -659,38 +658,75 @@ func GetIssueStats(repoID, uid, labelID, milestoneID, assigneeID int64, isShowCl
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	switch filterMode {
 | 
						switch filterMode {
 | 
				
			||||||
	case FM_ALL, FM_ASSIGN:
 | 
						case FM_ALL, FM_ASSIGN:
 | 
				
			||||||
		resutls, _ := x.Query(queryStr+baseCond, repoID, false)
 | 
							results, _ := x.Query(queryStr+baseCond, repoID, false)
 | 
				
			||||||
		stats.OpenCount = parseCountResult(resutls)
 | 
							stats.OpenCount = parseCountResult(results)
 | 
				
			||||||
		resutls, _ = x.Query(queryStr+baseCond, repoID, true)
 | 
							results, _ = x.Query(queryStr+baseCond, repoID, true)
 | 
				
			||||||
		stats.ClosedCount = parseCountResult(resutls)
 | 
							stats.ClosedCount = parseCountResult(results)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case FM_CREATE:
 | 
						case FM_CREATE:
 | 
				
			||||||
		baseCond += " AND poster_id=?"
 | 
							baseCond += " AND poster_id=?"
 | 
				
			||||||
		resutls, _ := x.Query(queryStr+baseCond, repoID, false, uid)
 | 
							results, _ := x.Query(queryStr+baseCond, repoID, false, uid)
 | 
				
			||||||
		stats.OpenCount = parseCountResult(resutls)
 | 
							stats.OpenCount = parseCountResult(results)
 | 
				
			||||||
		resutls, _ = x.Query(queryStr+baseCond, repoID, true, uid)
 | 
							results, _ = x.Query(queryStr+baseCond, repoID, true, uid)
 | 
				
			||||||
		stats.ClosedCount = parseCountResult(resutls)
 | 
							stats.ClosedCount = parseCountResult(results)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case FM_MENTION:
 | 
						case FM_MENTION:
 | 
				
			||||||
		queryStr += " INNER JOIN `issue_user` ON `issue`.id=`issue_user`.issue_id"
 | 
							queryStr += " INNER JOIN `issue_user` ON `issue`.id=`issue_user`.issue_id"
 | 
				
			||||||
		baseCond += " AND `issue_user`.uid=? AND `issue_user`.is_mentioned=?"
 | 
							baseCond += " AND `issue_user`.uid=? AND `issue_user`.is_mentioned=?"
 | 
				
			||||||
		resutls, _ := x.Query(queryStr+baseCond, repoID, false, uid, true)
 | 
							results, _ := x.Query(queryStr+baseCond, repoID, false, uid, true)
 | 
				
			||||||
		stats.OpenCount = parseCountResult(resutls)
 | 
							stats.OpenCount = parseCountResult(results)
 | 
				
			||||||
		resutls, _ = x.Query(queryStr+baseCond, repoID, true, uid, true)
 | 
							results, _ = x.Query(queryStr+baseCond, repoID, true, uid, true)
 | 
				
			||||||
		stats.ClosedCount = parseCountResult(resutls)
 | 
							stats.ClosedCount = parseCountResult(results)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return stats
 | 
						return stats
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetUserIssueStats returns issue statistic information for dashboard by given conditions.
 | 
					// GetUserIssueStats returns issue statistic information for dashboard by given conditions.
 | 
				
			||||||
func GetUserIssueStats(uid int64, filterMode int) *IssueStats {
 | 
					func GetUserIssueStats(repoID, uid int64, filterMode int) *IssueStats {
 | 
				
			||||||
	stats := &IssueStats{}
 | 
						stats := &IssueStats{}
 | 
				
			||||||
	issue := new(Issue)
 | 
						issue := new(Issue)
 | 
				
			||||||
	stats.AssignCount, _ = x.Where("assignee_id=?", uid).And("is_closed=?", false).Count(issue)
 | 
						stats.AssignCount, _ = x.Where("assignee_id=?", uid).And("is_closed=?", false).Count(issue)
 | 
				
			||||||
	stats.CreateCount, _ = x.Where("poster_id=?", uid).And("is_closed=?", false).Count(issue)
 | 
						stats.CreateCount, _ = x.Where("poster_id=?", uid).And("is_closed=?", false).Count(issue)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						queryStr := "SELECT COUNT(*) FROM `issue` "
 | 
				
			||||||
 | 
						baseCond := " WHERE issue.is_closed=?"
 | 
				
			||||||
 | 
						if repoID > 0 {
 | 
				
			||||||
 | 
							baseCond += " AND issue.repo_id=" + com.ToStr(repoID)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						switch filterMode {
 | 
				
			||||||
 | 
						case FM_ASSIGN:
 | 
				
			||||||
 | 
							baseCond += " AND assignee_id=" + com.ToStr(uid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case FM_CREATE:
 | 
				
			||||||
 | 
							baseCond += " AND poster_id=" + com.ToStr(uid)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						results, _ := x.Query(queryStr+baseCond, false)
 | 
				
			||||||
 | 
						stats.OpenCount = parseCountResult(results)
 | 
				
			||||||
 | 
						results, _ = x.Query(queryStr+baseCond, true)
 | 
				
			||||||
 | 
						stats.ClosedCount = parseCountResult(results)
 | 
				
			||||||
	return stats
 | 
						return stats
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetRepoIssueStats returns number of open and closed repository issues by given filter mode.
 | 
				
			||||||
 | 
					func GetRepoIssueStats(repoID, uid int64, filterMode int) (numOpen int64, numClosed int64) {
 | 
				
			||||||
 | 
						queryStr := "SELECT COUNT(*) FROM `issue` "
 | 
				
			||||||
 | 
						baseCond := " WHERE issue.repo_id=? AND issue.is_closed=?"
 | 
				
			||||||
 | 
						switch filterMode {
 | 
				
			||||||
 | 
						case FM_ASSIGN:
 | 
				
			||||||
 | 
							baseCond += " AND assignee_id=" + com.ToStr(uid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case FM_CREATE:
 | 
				
			||||||
 | 
							baseCond += " AND poster_id=" + com.ToStr(uid)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						results, _ := x.Query(queryStr+baseCond, repoID, false)
 | 
				
			||||||
 | 
						numOpen = parseCountResult(results)
 | 
				
			||||||
 | 
						results, _ = x.Query(queryStr+baseCond, repoID, true)
 | 
				
			||||||
 | 
						numClosed = parseCountResult(results)
 | 
				
			||||||
 | 
						return numOpen, numClosed
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func updateIssue(e Engine, issue *Issue) error {
 | 
					func updateIssue(e Engine, issue *Issue) error {
 | 
				
			||||||
	_, err := e.Id(issue.ID).AllCols().Update(issue)
 | 
						_, err := e.Id(issue.ID).AllCols().Update(issue)
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -221,6 +221,11 @@ func (repo *Repository) GetMilestoneByID(milestoneID int64) (*Milestone, error)
 | 
				
			|||||||
	return GetRepoMilestoneByID(repo.ID, milestoneID)
 | 
						return GetRepoMilestoneByID(repo.ID, milestoneID)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IssueStats returns number of open and closed repository issues by given filter mode.
 | 
				
			||||||
 | 
					func (repo *Repository) IssueStats(uid int64, filterMode int) (int64, int64) {
 | 
				
			||||||
 | 
						return GetRepoIssueStats(repo.ID, uid, filterMode)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (repo *Repository) GetMirror() (err error) {
 | 
					func (repo *Repository) GetMirror() (err error) {
 | 
				
			||||||
	repo.Mirror, err = GetMirror(repo.ID)
 | 
						repo.Mirror, err = GetMirror(repo.ID)
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								public/css/gogs.min.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								public/css/gogs.min.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										20
									
								
								public/less/_dashboard.less
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								public/less/_dashboard.less
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					.dashboard {
 | 
				
			||||||
 | 
						padding-top: 15px;
 | 
				
			||||||
 | 
						padding-bottom: @footer-margin * 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						&.issues {
 | 
				
			||||||
 | 
							.context.user.menu {
 | 
				
			||||||
 | 
								min-width: 200px;
 | 
				
			||||||
 | 
								.ui.header {
 | 
				
			||||||
 | 
							    font-size: 1rem;
 | 
				
			||||||
 | 
							    text-transform: none;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							.filter.menu {
 | 
				
			||||||
 | 
								.item.active {
 | 
				
			||||||
 | 
							    background-color: #4183c4;
 | 
				
			||||||
 | 
							    color: #FFF;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -79,47 +79,6 @@
 | 
				
			|||||||
	 	}
 | 
						 	}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	.page.buttons {
 | 
					 | 
				
			||||||
		padding-top: 15px;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	.issue.list {
 | 
					 | 
				
			||||||
		list-style: none;
 | 
					 | 
				
			||||||
		padding-top: 15px;
 | 
					 | 
				
			||||||
		>.item {
 | 
					 | 
				
			||||||
			padding-top: 15px;
 | 
					 | 
				
			||||||
			padding-bottom: 10px;
 | 
					 | 
				
			||||||
			border-bottom: 1px dashed #AAA;
 | 
					 | 
				
			||||||
			.title {
 | 
					 | 
				
			||||||
				color: #444;
 | 
					 | 
				
			||||||
				font-size: 15px;
 | 
					 | 
				
			||||||
				font-weight: bold;
 | 
					 | 
				
			||||||
				margin: 0 6px;
 | 
					 | 
				
			||||||
				&:hover {
 | 
					 | 
				
			||||||
					color: #000;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			.comment {
 | 
					 | 
				
			||||||
				padding-right: 10px;
 | 
					 | 
				
			||||||
				color: #666;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			.desc {
 | 
					 | 
				
			||||||
				padding-top: 5px;
 | 
					 | 
				
			||||||
				color: #999;
 | 
					 | 
				
			||||||
				a.milestone {
 | 
					 | 
				
			||||||
					padding-left: 5px;
 | 
					 | 
				
			||||||
					color: #999!important;
 | 
					 | 
				
			||||||
					&:hover {
 | 
					 | 
				
			||||||
						color: #000!important;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				.assignee {
 | 
					 | 
				
			||||||
					margin-top: -5px;
 | 
					 | 
				
			||||||
					margin-right: 5px;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	@comment-avatar-width: 3em;
 | 
						@comment-avatar-width: 3em;
 | 
				
			||||||
	&.new.issue {
 | 
						&.new.issue {
 | 
				
			||||||
		.comment.form {
 | 
							.comment.form {
 | 
				
			||||||
@@ -607,6 +566,48 @@
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.issue.list {
 | 
				
			||||||
 | 
						list-style: none;
 | 
				
			||||||
 | 
						padding-top: 15px;
 | 
				
			||||||
 | 
						>.item {
 | 
				
			||||||
 | 
							padding-top: 15px;
 | 
				
			||||||
 | 
							padding-bottom: 10px;
 | 
				
			||||||
 | 
							border-bottom: 1px dashed #AAA;
 | 
				
			||||||
 | 
							.title {
 | 
				
			||||||
 | 
								color: #444;
 | 
				
			||||||
 | 
								font-size: 15px;
 | 
				
			||||||
 | 
								font-weight: bold;
 | 
				
			||||||
 | 
								margin: 0 6px;
 | 
				
			||||||
 | 
								&:hover {
 | 
				
			||||||
 | 
									color: #000;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							.comment {
 | 
				
			||||||
 | 
								padding-right: 10px;
 | 
				
			||||||
 | 
								color: #666;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							.desc {
 | 
				
			||||||
 | 
								padding-top: 5px;
 | 
				
			||||||
 | 
								color: #999;
 | 
				
			||||||
 | 
								a.milestone {
 | 
				
			||||||
 | 
									padding-left: 5px;
 | 
				
			||||||
 | 
									color: #999!important;
 | 
				
			||||||
 | 
									&:hover {
 | 
				
			||||||
 | 
										color: #000!important;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								.assignee {
 | 
				
			||||||
 | 
									margin-top: -5px;
 | 
				
			||||||
 | 
									margin-right: 5px;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.page.buttons {
 | 
				
			||||||
 | 
						padding-top: 15px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.ui.comments {
 | 
					.ui.comments {
 | 
				
			||||||
	.dropzone {
 | 
						.dropzone {
 | 
				
			||||||
		width: 100%; 
 | 
							width: 100%; 
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,4 +6,5 @@
 | 
				
			|||||||
@import "_form";
 | 
					@import "_form";
 | 
				
			||||||
@import "_repository";
 | 
					@import "_repository";
 | 
				
			||||||
@import "_user";
 | 
					@import "_user";
 | 
				
			||||||
 | 
					@import "_dashboard";
 | 
				
			||||||
@import "_admin";
 | 
					@import "_admin";
 | 
				
			||||||
@@ -79,11 +79,11 @@ func Issues(ctx *middleware.Context) {
 | 
				
			|||||||
	filterMode := models.FM_ALL
 | 
						filterMode := models.FM_ALL
 | 
				
			||||||
	switch viewType {
 | 
						switch viewType {
 | 
				
			||||||
	case "assigned":
 | 
						case "assigned":
 | 
				
			||||||
		assigneeID = ctx.User.Id
 | 
					 | 
				
			||||||
		filterMode = models.FM_ASSIGN
 | 
							filterMode = models.FM_ASSIGN
 | 
				
			||||||
 | 
							assigneeID = ctx.User.Id
 | 
				
			||||||
	case "created_by":
 | 
						case "created_by":
 | 
				
			||||||
		posterID = ctx.User.Id
 | 
					 | 
				
			||||||
		filterMode = models.FM_CREATE
 | 
							filterMode = models.FM_CREATE
 | 
				
			||||||
 | 
							posterID = ctx.User.Id
 | 
				
			||||||
	case "mentioned":
 | 
						case "mentioned":
 | 
				
			||||||
		filterMode = models.FM_MENTION
 | 
							filterMode = models.FM_MENTION
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -97,7 +97,7 @@ func Issues(ctx *middleware.Context) {
 | 
				
			|||||||
	selectLabels := ctx.Query("labels")
 | 
						selectLabels := ctx.Query("labels")
 | 
				
			||||||
	milestoneID := ctx.QueryInt64("milestone")
 | 
						milestoneID := ctx.QueryInt64("milestone")
 | 
				
			||||||
	isShowClosed := ctx.Query("state") == "closed"
 | 
						isShowClosed := ctx.Query("state") == "closed"
 | 
				
			||||||
	issueStats := models.GetIssueStats(repo.ID, uid, com.StrTo(selectLabels).MustInt64(), milestoneID, assigneeID, isShowClosed, filterMode)
 | 
						issueStats := models.GetIssueStats(repo.ID, uid, com.StrTo(selectLabels).MustInt64(), milestoneID, assigneeID, filterMode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	page := ctx.QueryInt("page")
 | 
						page := ctx.QueryInt("page")
 | 
				
			||||||
	if page <= 1 {
 | 
						if page <= 1 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,10 +10,10 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/Unknwon/com"
 | 
						"github.com/Unknwon/com"
 | 
				
			||||||
 | 
						"github.com/Unknwon/paginater"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/gogits/gogs/models"
 | 
						"github.com/gogits/gogs/models"
 | 
				
			||||||
	"github.com/gogits/gogs/modules/base"
 | 
						"github.com/gogits/gogs/modules/base"
 | 
				
			||||||
	"github.com/gogits/gogs/modules/log"
 | 
					 | 
				
			||||||
	"github.com/gogits/gogs/modules/middleware"
 | 
						"github.com/gogits/gogs/modules/middleware"
 | 
				
			||||||
	"github.com/gogits/gogs/modules/setting"
 | 
						"github.com/gogits/gogs/modules/setting"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -21,18 +21,13 @@ import (
 | 
				
			|||||||
const (
 | 
					const (
 | 
				
			||||||
	DASHBOARD base.TplName = "user/dashboard/dashboard"
 | 
						DASHBOARD base.TplName = "user/dashboard/dashboard"
 | 
				
			||||||
	PULLS     base.TplName = "user/dashboard/pulls"
 | 
						PULLS     base.TplName = "user/dashboard/pulls"
 | 
				
			||||||
	ISSUES    base.TplName = "user/issues"
 | 
						ISSUES    base.TplName = "user/dashboard/issues"
 | 
				
			||||||
	STARS     base.TplName = "user/stars"
 | 
						STARS     base.TplName = "user/stars"
 | 
				
			||||||
	PROFILE   base.TplName = "user/profile"
 | 
						PROFILE   base.TplName = "user/profile"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Dashboard(ctx *middleware.Context) {
 | 
					func getDashboardContextUser(ctx *middleware.Context) *models.User {
 | 
				
			||||||
	ctx.Data["Title"] = ctx.Tr("dashboard")
 | 
						ctxUser := ctx.User
 | 
				
			||||||
	ctx.Data["PageIsDashboard"] = true
 | 
					 | 
				
			||||||
	ctx.Data["PageIsNews"] = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var ctxUser *models.User
 | 
					 | 
				
			||||||
	// Check context type.
 | 
					 | 
				
			||||||
	orgName := ctx.Params(":org")
 | 
						orgName := ctx.Params(":org")
 | 
				
			||||||
	if len(orgName) > 0 {
 | 
						if len(orgName) > 0 {
 | 
				
			||||||
		// Organization.
 | 
							// Organization.
 | 
				
			||||||
@@ -43,10 +38,33 @@ func Dashboard(ctx *middleware.Context) {
 | 
				
			|||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				ctx.Handle(500, "GetUserByName", err)
 | 
									ctx.Handle(500, "GetUserByName", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return
 | 
								return nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ctxUser = org
 | 
							ctxUser = org
 | 
				
			||||||
	} else {
 | 
						}
 | 
				
			||||||
 | 
						ctx.Data["ContextUser"] = ctxUser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := ctx.User.GetOrganizations(); err != nil {
 | 
				
			||||||
 | 
							ctx.Handle(500, "GetOrganizations", err)
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ctx.Data["Orgs"] = ctx.User.Orgs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ctxUser
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Dashboard(ctx *middleware.Context) {
 | 
				
			||||||
 | 
						ctx.Data["Title"] = ctx.Tr("dashboard")
 | 
				
			||||||
 | 
						ctx.Data["PageIsDashboard"] = true
 | 
				
			||||||
 | 
						ctx.Data["PageIsNews"] = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctxUser := getDashboardContextUser(ctx)
 | 
				
			||||||
 | 
						if ctx.Written() {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check context type.
 | 
				
			||||||
 | 
						if !ctxUser.IsOrganization() {
 | 
				
			||||||
		// Normal user.
 | 
							// Normal user.
 | 
				
			||||||
		ctxUser = ctx.User
 | 
							ctxUser = ctx.User
 | 
				
			||||||
		collaborates, err := ctx.User.GetAccessibleRepositories()
 | 
							collaborates, err := ctx.User.GetAccessibleRepositories()
 | 
				
			||||||
@@ -63,13 +81,6 @@ func Dashboard(ctx *middleware.Context) {
 | 
				
			|||||||
		ctx.Data["CollaborateCount"] = len(repositories)
 | 
							ctx.Data["CollaborateCount"] = len(repositories)
 | 
				
			||||||
		ctx.Data["CollaborativeRepos"] = repositories
 | 
							ctx.Data["CollaborativeRepos"] = repositories
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.Data["ContextUser"] = ctxUser
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err := ctx.User.GetOrganizations(); err != nil {
 | 
					 | 
				
			||||||
		ctx.Handle(500, "GetOrganizations", err)
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ctx.Data["Orgs"] = ctx.User.Orgs
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	repos, err := models.GetRepositories(ctxUser.Id, true)
 | 
						repos, err := models.GetRepositories(ctxUser.Id, true)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -142,6 +153,138 @@ func Pulls(ctx *middleware.Context) {
 | 
				
			|||||||
	ctx.HTML(200, PULLS)
 | 
						ctx.HTML(200, PULLS)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Issues(ctx *middleware.Context) {
 | 
				
			||||||
 | 
						ctx.Data["Title"] = ctx.Tr("issues")
 | 
				
			||||||
 | 
						ctx.Data["PageIsIssues"] = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctxUser := getDashboardContextUser(ctx)
 | 
				
			||||||
 | 
						if ctx.Written() {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Organization does not have view type and filter mode.
 | 
				
			||||||
 | 
						var (
 | 
				
			||||||
 | 
							viewType   string
 | 
				
			||||||
 | 
							filterMode = models.FM_ALL
 | 
				
			||||||
 | 
							assigneeID int64
 | 
				
			||||||
 | 
							posterID   int64
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						if ctxUser.IsOrganization() {
 | 
				
			||||||
 | 
							viewType = "all"
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							viewType = ctx.Query("type")
 | 
				
			||||||
 | 
							types := []string{"assigned", "created_by"}
 | 
				
			||||||
 | 
							if !com.IsSliceContainsStr(types, viewType) {
 | 
				
			||||||
 | 
								viewType = "all"
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch viewType {
 | 
				
			||||||
 | 
							case "assigned":
 | 
				
			||||||
 | 
								filterMode = models.FM_ASSIGN
 | 
				
			||||||
 | 
								assigneeID = ctxUser.Id
 | 
				
			||||||
 | 
							case "created_by":
 | 
				
			||||||
 | 
								filterMode = models.FM_CREATE
 | 
				
			||||||
 | 
								posterID = ctxUser.Id
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						repoID := ctx.QueryInt64("repo")
 | 
				
			||||||
 | 
						isShowClosed := ctx.Query("state") == "closed"
 | 
				
			||||||
 | 
						issueStats := models.GetUserIssueStats(repoID, ctxUser.Id, filterMode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						page := ctx.QueryInt("page")
 | 
				
			||||||
 | 
						if page <= 1 {
 | 
				
			||||||
 | 
							page = 1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var total int
 | 
				
			||||||
 | 
						if !isShowClosed {
 | 
				
			||||||
 | 
							total = int(issueStats.OpenCount)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							total = int(issueStats.ClosedCount)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ctx.Data["Page"] = paginater.New(total, setting.IssuePagingNum, page, 5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Get repositories.
 | 
				
			||||||
 | 
						repos, err := models.GetRepositories(ctxUser.Id, true)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.Handle(500, "GetRepositories", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						repoIDs := make([]int64, 0, len(repos))
 | 
				
			||||||
 | 
						showRepos := make([]*models.Repository, 0, len(repos))
 | 
				
			||||||
 | 
						for _, repo := range repos {
 | 
				
			||||||
 | 
							if repo.NumIssues == 0 {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							repoIDs = append(repoIDs, repo.ID)
 | 
				
			||||||
 | 
							repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
 | 
				
			||||||
 | 
							issueStats.AllCount += int64(repo.NumOpenIssues)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if repo.ID == repoID {
 | 
				
			||||||
 | 
								repo.NumOpenIssues = int(issueStats.OpenCount)
 | 
				
			||||||
 | 
								repo.NumClosedIssues = int(issueStats.ClosedCount)
 | 
				
			||||||
 | 
							} else if filterMode != models.FM_ALL && repo.NumIssues > 0 {
 | 
				
			||||||
 | 
								// Calculate repository issue count with filter mode.
 | 
				
			||||||
 | 
								numOpen, numClosed := repo.IssueStats(ctxUser.Id, filterMode)
 | 
				
			||||||
 | 
								repo.NumOpenIssues, repo.NumClosedIssues = int(numOpen), int(numClosed)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if repo.ID == repoID ||
 | 
				
			||||||
 | 
								(isShowClosed && repo.NumClosedIssues > 0) ||
 | 
				
			||||||
 | 
								(!isShowClosed && repo.NumOpenIssues > 0) {
 | 
				
			||||||
 | 
								showRepos = append(showRepos, repo)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ctx.Data["Repos"] = showRepos
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if repoID > 0 {
 | 
				
			||||||
 | 
							repoIDs = []int64{repoID}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Get issues.
 | 
				
			||||||
 | 
						issues, err := models.Issues(ctxUser.Id, assigneeID, repoID, posterID, 0,
 | 
				
			||||||
 | 
							page, isShowClosed, false, "", "")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.Handle(500, "Issues: %v", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Get posters and repository.
 | 
				
			||||||
 | 
						for i := range issues {
 | 
				
			||||||
 | 
							issues[i].Repo, err = models.GetRepositoryByID(issues[i].RepoID)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								ctx.Handle(500, "GetRepositoryByID", fmt.Errorf("[#%d]%v", issues[i].ID, err))
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err = issues[i].Repo.GetOwner(); err != nil {
 | 
				
			||||||
 | 
								ctx.Handle(500, "GetOwner", fmt.Errorf("[#%d]%v", issues[i].ID, err))
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err = issues[i].GetPoster(); err != nil {
 | 
				
			||||||
 | 
								ctx.Handle(500, "GetPoster", fmt.Errorf("[#%d]%v", issues[i].ID, err))
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ctx.Data["Issues"] = issues
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.Data["IssueStats"] = issueStats
 | 
				
			||||||
 | 
						ctx.Data["ViewType"] = viewType
 | 
				
			||||||
 | 
						ctx.Data["RepoID"] = repoID
 | 
				
			||||||
 | 
						ctx.Data["IsShowClosed"] = isShowClosed
 | 
				
			||||||
 | 
						if isShowClosed {
 | 
				
			||||||
 | 
							ctx.Data["State"] = "closed"
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ctx.Data["State"] = "open"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.HTML(200, ISSUES)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ShowSSHKeys(ctx *middleware.Context, uid int64) {
 | 
					func ShowSSHKeys(ctx *middleware.Context, uid int64) {
 | 
				
			||||||
	keys, err := models.ListPublicKeys(uid)
 | 
						keys, err := models.ListPublicKeys(uid)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -256,136 +399,3 @@ func Email2User(ctx *middleware.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.Redirect(setting.AppSubUrl + "/user/" + u.Name)
 | 
						ctx.Redirect(setting.AppSubUrl + "/user/" + u.Name)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
func Issues(ctx *middleware.Context) {
 | 
					 | 
				
			||||||
	ctx.Data["Title"] = ctx.Tr("issues")
 | 
					 | 
				
			||||||
	ctx.Data["PageIsDashboard"] = true
 | 
					 | 
				
			||||||
	ctx.Data["PageIsIssues"] = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	viewType := ctx.Query("type")
 | 
					 | 
				
			||||||
	types := []string{"assigned", "created_by"}
 | 
					 | 
				
			||||||
	if !com.IsSliceContainsStr(types, viewType) {
 | 
					 | 
				
			||||||
		viewType = "all"
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	isShowClosed := ctx.Query("state") == "closed"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var filterMode int
 | 
					 | 
				
			||||||
	switch viewType {
 | 
					 | 
				
			||||||
	case "assigned":
 | 
					 | 
				
			||||||
		filterMode = models.FM_ASSIGN
 | 
					 | 
				
			||||||
	case "created_by":
 | 
					 | 
				
			||||||
		filterMode = models.FM_CREATE
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	repoId, _ := com.StrTo(ctx.Query("repoid")).Int64()
 | 
					 | 
				
			||||||
	issueStats := models.GetUserIssueStats(ctx.User.Id, filterMode)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Get all repositories.
 | 
					 | 
				
			||||||
	repos, err := models.GetRepositories(ctx.User.Id, true)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		ctx.Handle(500, "user.Issues(GetRepositories)", err)
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	repoIds := make([]int64, 0, len(repos))
 | 
					 | 
				
			||||||
	showRepos := make([]*models.Repository, 0, len(repos))
 | 
					 | 
				
			||||||
	for _, repo := range repos {
 | 
					 | 
				
			||||||
		if repo.NumIssues == 0 {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		repoIds = append(repoIds, repo.ID)
 | 
					 | 
				
			||||||
		repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
 | 
					 | 
				
			||||||
		issueStats.AllCount += int64(repo.NumOpenIssues)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if isShowClosed {
 | 
					 | 
				
			||||||
			if repo.NumClosedIssues > 0 {
 | 
					 | 
				
			||||||
				if filterMode == models.FM_CREATE {
 | 
					 | 
				
			||||||
					repo.NumClosedIssues = int(models.GetIssueCountByPoster(ctx.User.Id, repo.ID, isShowClosed))
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				showRepos = append(showRepos, repo)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			if repo.NumOpenIssues > 0 {
 | 
					 | 
				
			||||||
				if filterMode == models.FM_CREATE {
 | 
					 | 
				
			||||||
					repo.NumOpenIssues = int(models.GetIssueCountByPoster(ctx.User.Id, repo.ID, isShowClosed))
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				showRepos = append(showRepos, repo)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if repoId > 0 {
 | 
					 | 
				
			||||||
		repoIds = []int64{repoId}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	page, _ := com.StrTo(ctx.Query("page")).Int()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Get all issues.
 | 
					 | 
				
			||||||
	var ius []*models.IssueUser
 | 
					 | 
				
			||||||
	switch viewType {
 | 
					 | 
				
			||||||
	case "assigned":
 | 
					 | 
				
			||||||
		fallthrough
 | 
					 | 
				
			||||||
	case "created_by":
 | 
					 | 
				
			||||||
		ius, err = models.GetIssueUserPairsByMode(ctx.User.Id, repoId, isShowClosed, page, filterMode)
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		ius, err = models.GetIssueUserPairsByRepoIds(repoIds, isShowClosed, page)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		ctx.Handle(500, "user.Issues(GetAllIssueUserPairs)", err)
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	issues := make([]*models.Issue, len(ius))
 | 
					 | 
				
			||||||
	for i := range ius {
 | 
					 | 
				
			||||||
		issues[i], err = models.GetIssueByID(ius[i].IssueID)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			if models.IsErrIssueNotExist(err) {
 | 
					 | 
				
			||||||
				log.Warn("user.Issues(GetIssueById #%d): issue not exist", ius[i].IssueID)
 | 
					 | 
				
			||||||
				continue
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				ctx.Handle(500, fmt.Sprintf("user.Issues(GetIssueById #%d)", ius[i].IssueID), err)
 | 
					 | 
				
			||||||
				return
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		issues[i].Repo, err = models.GetRepositoryByID(issues[i].RepoID)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			if models.IsErrRepoNotExist(err) {
 | 
					 | 
				
			||||||
				log.Warn("GetRepositoryById[%d]: repository not exist", issues[i].RepoID)
 | 
					 | 
				
			||||||
				continue
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				ctx.Handle(500, fmt.Sprintf("GetRepositoryById[%d]", issues[i].RepoID), err)
 | 
					 | 
				
			||||||
				return
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if err = issues[i].Repo.GetOwner(); err != nil {
 | 
					 | 
				
			||||||
			ctx.Handle(500, "user.Issues(GetOwner)", err)
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if err = issues[i].GetPoster(); err != nil {
 | 
					 | 
				
			||||||
			ctx.Handle(500, "user.Issues(GetUserById)", err)
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx.Data["RepoId"] = repoId
 | 
					 | 
				
			||||||
	ctx.Data["Repos"] = showRepos
 | 
					 | 
				
			||||||
	ctx.Data["Issues"] = issues
 | 
					 | 
				
			||||||
	ctx.Data["ViewType"] = viewType
 | 
					 | 
				
			||||||
	ctx.Data["IssueStats"] = issueStats
 | 
					 | 
				
			||||||
	ctx.Data["IsShowClosed"] = isShowClosed
 | 
					 | 
				
			||||||
	if isShowClosed {
 | 
					 | 
				
			||||||
		ctx.Data["State"] = "closed"
 | 
					 | 
				
			||||||
		ctx.Data["ShowCount"] = issueStats.ClosedCount
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		ctx.Data["ShowCount"] = issueStats.OpenCount
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx.Data["ContextUser"] = ctx.User
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx.HTML(200, ISSUES)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,6 +62,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
							{{if .IsSigned}}
 | 
												{{if .IsSigned}}
 | 
				
			||||||
							<a class="item{{if .PageIsDashboard}} active{{end}}" href="{{AppSubUrl}}/">{{.i18n.Tr "dashboard"}}</a>
 | 
												<a class="item{{if .PageIsDashboard}} active{{end}}" href="{{AppSubUrl}}/">{{.i18n.Tr "dashboard"}}</a>
 | 
				
			||||||
 | 
												<a class="item{{if .PageIsIssues}} active{{end}}" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a>
 | 
				
			||||||
							{{else}}
 | 
												{{else}}
 | 
				
			||||||
							<a class="item{{if .PageIsHome}} active{{end}}" href="{{AppSubUrl}}/">{{.i18n.Tr "home"}}</a>
 | 
												<a class="item{{if .PageIsHome}} active{{end}}" href="{{AppSubUrl}}/">{{.i18n.Tr "home"}}</a>
 | 
				
			||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
@@ -75,7 +76,6 @@
 | 
				
			|||||||
							</div> -->
 | 
												</div> -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							{{if .IsSigned}}
 | 
												{{if .IsSigned}}
 | 
				
			||||||
							<a class="item{{if .PageIsIssues}} active{{end}}" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a>
 | 
					 | 
				
			||||||
							<div class="right menu">
 | 
												<div class="right menu">
 | 
				
			||||||
								<div class="ui dropdown head link jump item poping up" data-content="{{.i18n.Tr "create_new"}}" data-variation="tiny inverted">
 | 
													<div class="ui dropdown head link jump item poping up" data-content="{{.i18n.Tr "create_new"}}" data-variation="tiny inverted">
 | 
				
			||||||
									<span class="text">
 | 
														<span class="text">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,9 +10,11 @@
 | 
				
			|||||||
	  <a class="{{if .PageIsSettingsHooks}}active{{end}} item" href="{{.RepoLink}}/settings/hooks">
 | 
						  <a class="{{if .PageIsSettingsHooks}}active{{end}} item" href="{{.RepoLink}}/settings/hooks">
 | 
				
			||||||
	    {{.i18n.Tr "repo.settings.hooks"}}
 | 
						    {{.i18n.Tr "repo.settings.hooks"}}
 | 
				
			||||||
	  </a>
 | 
						  </a>
 | 
				
			||||||
 | 
						  {{if or .SignedUser.AllowGitHook .SignedUser.IsAdmin}}
 | 
				
			||||||
	  <a class="{{if .PageIsSettingsGitHooks}}active{{end}} item" href="{{.RepoLink}}/settings/hooks/git">
 | 
						  <a class="{{if .PageIsSettingsGitHooks}}active{{end}} item" href="{{.RepoLink}}/settings/hooks/git">
 | 
				
			||||||
	    {{.i18n.Tr "repo.settings.githooks"}}
 | 
						    {{.i18n.Tr "repo.settings.githooks"}}
 | 
				
			||||||
	  </a>
 | 
						  </a>
 | 
				
			||||||
 | 
						  {{end}}
 | 
				
			||||||
	  <a class="{{if .PageIsSettingsKeys}}active{{end}} item" href="{{.RepoLink}}/settings/keys">
 | 
						  <a class="{{if .PageIsSettingsKeys}}active{{end}} item" href="{{.RepoLink}}/settings/keys">
 | 
				
			||||||
	    {{.i18n.Tr "repo.settings.deploy_keys"}}
 | 
						    {{.i18n.Tr "repo.settings.deploy_keys"}}
 | 
				
			||||||
	  </a>
 | 
						  </a>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										86
									
								
								templates/user/dashboard/issues.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								templates/user/dashboard/issues.tmpl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					{{template "base/head" .}}
 | 
				
			||||||
 | 
					<div class="dashboard issues">
 | 
				
			||||||
 | 
					  {{template "user/dashboard/navbar" .}}
 | 
				
			||||||
 | 
					  <div class="ui container">
 | 
				
			||||||
 | 
					  	<div class="ui grid">
 | 
				
			||||||
 | 
					  		<div class="four wide column">
 | 
				
			||||||
 | 
					  			<div class="ui secondary vertical filter menu">
 | 
				
			||||||
 | 
					  				<a class="{{if eq .ViewType "all"}}active{{end}} item" href="{{.Link}}?repo={{.RepoID}}&state={{.State}}">
 | 
				
			||||||
 | 
					  					{{.i18n.Tr "home.issues.in_your_repos"}}
 | 
				
			||||||
 | 
					  					<strong class="ui right">{{.IssueStats.AllCount}}</strong>
 | 
				
			||||||
 | 
					  				</a>
 | 
				
			||||||
 | 
					  				<a class="{{if eq .ViewType "assigned"}}active{{end}} item" href="{{.Link}}?type=assigned&repo={{.RepoID}}&state={{.State}}">
 | 
				
			||||||
 | 
					  					{{.i18n.Tr "repo.issues.filter_type.assigned_to_you"}}
 | 
				
			||||||
 | 
					  					<strong class="ui right">{{.IssueStats.AssignCount}}</strong>
 | 
				
			||||||
 | 
					  				</a>
 | 
				
			||||||
 | 
					  				<a class="{{if eq .ViewType "created_by"}}active{{end}} item" href="{{.Link}}?type=created_by&repo={{.RepoID}}&state={{.State}}">
 | 
				
			||||||
 | 
					  					{{.i18n.Tr "repo.issues.filter_type.created_by_you"}}
 | 
				
			||||||
 | 
					  					<strong class="ui right">{{.IssueStats.CreateCount}}</strong>
 | 
				
			||||||
 | 
					  				</a>
 | 
				
			||||||
 | 
					  				<div class="ui divider"></div>
 | 
				
			||||||
 | 
					          {{range .Repos}}
 | 
				
			||||||
 | 
					          <a class="{{if eq $.RepoID .ID}}active{{end}} item" href="{{$.Link}}?type={{$.ViewType}}{{if not (eq $.RepoID .ID)}}&repo={{.ID}}{{end}}&state={{$.State}}">{{$.SignedUser.Name}}/{{.Name}} <strong class="ui right">{{if $.IsShowClosed}}{{.NumClosedIssues}}{{else}}{{.NumOpenIssues}}{{end}}</strong></a>
 | 
				
			||||||
 | 
					          {{end}}
 | 
				
			||||||
 | 
					  			</div>
 | 
				
			||||||
 | 
					  		</div>
 | 
				
			||||||
 | 
								<div class="twelve wide column content">
 | 
				
			||||||
 | 
									<div class="ui tiny buttons">
 | 
				
			||||||
 | 
									  <a class="ui green basic button {{if not .IsShowClosed}}active{{end}}" href="{{.Link}}?type={{$.ViewType}}&repo={{.RepoID}}&state=open">
 | 
				
			||||||
 | 
									  	<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="{{.Link}}?type={{$.ViewType}}&repo={{.RepoID}}&state=closed">
 | 
				
			||||||
 | 
									  	<i class="octicon octicon-issue-closed"></i>
 | 
				
			||||||
 | 
									  	{{.i18n.Tr "repo.issues.close_tab" .IssueStats.ClosedCount}}
 | 
				
			||||||
 | 
									  </a>
 | 
				
			||||||
 | 
									</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									<div class="issue list">
 | 
				
			||||||
 | 
										{{range .Issues}}
 | 
				
			||||||
 | 
										{{ $timeStr:= TimeSince .Created $.Lang }}
 | 
				
			||||||
 | 
							      <li class="item">
 | 
				
			||||||
 | 
							      	<div class="ui label">#{{.ID}}</div>
 | 
				
			||||||
 | 
							      	<a class="title" href="{{AppSubUrl}}/{{.Repo.Owner.Name}}/{{.Repo.Name}}/issues/{{.Index}}">{{.Name}}</a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							      	{{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 | Safe}}
 | 
				
			||||||
 | 
								        {{if .Assignee}}
 | 
				
			||||||
 | 
												<a class="ui right assignee poping up" href="{{.Assignee.HomeLink}}" data-content="{{.Assignee.Name}}" data-variation="inverted" data-position="left center">
 | 
				
			||||||
 | 
													<img class="ui avatar image" src="{{.Assignee.AvatarLink}}">
 | 
				
			||||||
 | 
												</a>
 | 
				
			||||||
 | 
								        {{end}}
 | 
				
			||||||
 | 
							        </p>
 | 
				
			||||||
 | 
							      </li>
 | 
				
			||||||
 | 
							      {{end}}
 | 
				
			||||||
 | 
										
 | 
				
			||||||
 | 
										{{with .Page}}
 | 
				
			||||||
 | 
										{{if gt .TotalPages 1}}
 | 
				
			||||||
 | 
										<div class="center page buttons">
 | 
				
			||||||
 | 
											<div class="ui borderless pagination menu">
 | 
				
			||||||
 | 
											  <a class="{{if not .HasPrevious}}disabled{{end}} item" {{if .HasPrevious}}href="{{$.Link}}?type={{$.ViewType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&page={{.Previous}}"{{end}}>
 | 
				
			||||||
 | 
											    <i class="left arrow icon"></i> {{$.i18n.Tr "repo.issues.previous"}}
 | 
				
			||||||
 | 
											  </a>
 | 
				
			||||||
 | 
												{{range .Pages}}
 | 
				
			||||||
 | 
												{{if eq .Num -1}}
 | 
				
			||||||
 | 
												<a class="disabled item">...</a>
 | 
				
			||||||
 | 
												{{else}}
 | 
				
			||||||
 | 
												<a class="{{if .IsCurrent}}active{{end}} item" {{if not .IsCurrent}}href="{{$.Link}}?type={{$.ViewType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&page={{.Num}}"{{end}}>{{.Num}}</a>
 | 
				
			||||||
 | 
												{{end}}
 | 
				
			||||||
 | 
												{{end}}
 | 
				
			||||||
 | 
											  <a class="{{if not .HasNext}}disabled{{end}} item" {{if .HasNext}}href="{{$.Link}}?type={{$.ViewType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&page={{.Next}}"{{end}}>
 | 
				
			||||||
 | 
											    {{$.i18n.Tr "repo.issues.next"}} <i class="icon right arrow"></i>
 | 
				
			||||||
 | 
											  </a>
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
										</div>
 | 
				
			||||||
 | 
										{{end}}
 | 
				
			||||||
 | 
										{{end}}
 | 
				
			||||||
 | 
									</div>
 | 
				
			||||||
 | 
							  </div>
 | 
				
			||||||
 | 
					  	</div>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					{{template "base/footer" .}}
 | 
				
			||||||
							
								
								
									
										30
									
								
								templates/user/dashboard/navbar.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								templates/user/dashboard/navbar.tmpl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					<div class="ui container">
 | 
				
			||||||
 | 
					  <div class="ui floating dropdown link jump">
 | 
				
			||||||
 | 
					    <span class="text">
 | 
				
			||||||
 | 
					    	<img class="ui avatar image" src="{{.ContextUser.AvatarLink}}">
 | 
				
			||||||
 | 
					  		{{.ContextUser.Name}}
 | 
				
			||||||
 | 
					    	<i class="dropdown icon"></i>
 | 
				
			||||||
 | 
					  	</span>
 | 
				
			||||||
 | 
					    <div class="context user menu" tabindex="-1">
 | 
				
			||||||
 | 
								<div class="ui header">
 | 
				
			||||||
 | 
									{{.i18n.Tr "home.switch_dashboard_context"}}
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
 | 
					    	<a class="{{if eq .ContextUser.Id .SignedUser.Id}}active selected{{end}} item" href="{{AppSubUrl}}/issues">
 | 
				
			||||||
 | 
					      	<img class="ui image" src="{{.SignedUser.AvatarLink}}">
 | 
				
			||||||
 | 
					    		{{.SignedUser.Name}}
 | 
				
			||||||
 | 
					    	</a>
 | 
				
			||||||
 | 
					    	{{range .Orgs}}
 | 
				
			||||||
 | 
					    	{{if .IsOwnedBy $.SignedUser.Id}}
 | 
				
			||||||
 | 
					    	<a class="{{if eq $.ContextUser.Id .Id}}active selected{{end}} item" href="{{AppSubUrl}}/org/{{.Name}}/issues">
 | 
				
			||||||
 | 
					      	<img class="ui image" src="{{.AvatarLink}}">
 | 
				
			||||||
 | 
					    		{{.Name}}
 | 
				
			||||||
 | 
					    	</a>
 | 
				
			||||||
 | 
					    	{{end}}
 | 
				
			||||||
 | 
					    	{{end}}
 | 
				
			||||||
 | 
					    	<a class="item" href="{{AppSubUrl}}/org/create">
 | 
				
			||||||
 | 
					    		<i class="octicon octicon-repo-create"></i>   {{.i18n.Tr "new_org"}}
 | 
				
			||||||
 | 
					    	</a>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					<div class="ui divider"></div>
 | 
				
			||||||
@@ -1,44 +0,0 @@
 | 
				
			|||||||
{{template "ng/base/head" .}}
 | 
					 | 
				
			||||||
{{template "ng/base/header" .}}
 | 
					 | 
				
			||||||
{{template "user/dashboard/nav" .}}
 | 
					 | 
				
			||||||
<div id="dashboard-wrapper">
 | 
					 | 
				
			||||||
	<div id="dashboard" class="container" data-page="user">
 | 
					 | 
				
			||||||
		{{if .HasInfo}}<div class="alert alert-info">{{.InfoMsg}}</div>{{end}}
 | 
					 | 
				
			||||||
		<div id="issue">
 | 
					 | 
				
			||||||
		    <div class="left grid-1-5 filter-list">
 | 
					 | 
				
			||||||
		        <ul class="list-unstyled menu menu-vertical">
 | 
					 | 
				
			||||||
		            <li><a href="{{AppSubUrl}}/issues?state={{.State}}&repoid={{.RepoId}}" class="radius{{if eq .ViewType "all"}} active{{end}}" >In your repositories <strong class="pull-right">{{.IssueStats.AllCount}}</strong></a></li>
 | 
					 | 
				
			||||||
		            <li><a href="{{AppSubUrl}}/issues?type=assigned&repoid={{.RepoId}}&state={{.State}}" class="radius{{if eq .ViewType "assigned"}} active{{end}}">Assigned to you <strong class="pull-right">{{.IssueStats.AssignCount}}</strong></a></li>
 | 
					 | 
				
			||||||
		            <li><a href="{{AppSubUrl}}/issues?type=created_by&repoid={{.RepoId}}&state={{.State}}" class="radius{{if eq .ViewType "created_by"}} active{{end}}">Created by you <strong class="pull-right">{{.IssueStats.CreateCount}}</strong></a></li>
 | 
					 | 
				
			||||||
		            <li><hr/></li>
 | 
					 | 
				
			||||||
		            {{range .Repos}}
 | 
					 | 
				
			||||||
		            <li><a href="{{AppSubUrl}}/issues?type={{$.ViewType}}{{if eq $.RepoId .ID}}{{else}}&repoid={{.ID}}{{end}}&state={{$.State}}" class="radius{{if eq $.RepoId .ID}} active{{end}}">{{$.SignedUser.Name}}/{{.Name}} <strong class="pull-right">{{if $.IsShowClosed}}{{.NumClosedIssues}}{{else}}{{.NumOpenIssues}}{{end}}</strong></a></li>
 | 
					 | 
				
			||||||
		            {{end}}
 | 
					 | 
				
			||||||
		        </ul>
 | 
					 | 
				
			||||||
		    </div>
 | 
					 | 
				
			||||||
		    <div class="right grid-3-4">
 | 
					 | 
				
			||||||
		        <div class="filter-option">
 | 
					 | 
				
			||||||
		            <div class="btn-group">
 | 
					 | 
				
			||||||
		                <a class="btn btn-white btn-small issue-open{{if not .IsShowClosed}} active{{end}}" href="{{AppSubUrl}}/issues?type={{.ViewType}}&repoid={{.RepoId}}">Open</a>
 | 
					 | 
				
			||||||
		                <a class="btn btn-white btn-small issue-close{{if .IsShowClosed}} active{{end}}" href="{{AppSubUrl}}/issues?type={{.ViewType}}&repoid={{.RepoId}}&state=closed">Closed</a>
 | 
					 | 
				
			||||||
		            </div>
 | 
					 | 
				
			||||||
		        </div>
 | 
					 | 
				
			||||||
		        <div class="issues list-group">
 | 
					 | 
				
			||||||
		            {{range .Issues}}{{if .}}
 | 
					 | 
				
			||||||
		            <div class="list-group-item issue-item" id="issue-{{.ID}}" onclick="window.location.href='{{AppSubUrl}}/{{.Repo.Owner.Name}}/{{.Repo.Name}}/issues/{{.Index}}'">
 | 
					 | 
				
			||||||
		                <span class="number pull-right">#{{.Index}}</span>
 | 
					 | 
				
			||||||
		                <h5 class="title"><a href="{{AppSubUrl}}/{{.Repo.Owner.Name}}/{{.Repo.Name}}/issues/{{.Index}}">{{.Name}}</a></h5>
 | 
					 | 
				
			||||||
		                <p class="info">
 | 
					 | 
				
			||||||
		                    <span class="author"><img class="avatar" src="{{.Poster.AvatarLink}}" alt="" width="20"/>
 | 
					 | 
				
			||||||
		                    <a href="{{AppSubUrl}}/{{.Poster.Name}}">{{.Poster.Name}}</a></span>
 | 
					 | 
				
			||||||
		                    <span class="time">{{TimeSince .Created $.Lang}}</span>
 | 
					 | 
				
			||||||
		                    <span class="comment"><i class="fa fa-comments"></i> {{.NumComments}}</span>
 | 
					 | 
				
			||||||
		                </p>
 | 
					 | 
				
			||||||
		            </div>
 | 
					 | 
				
			||||||
		            {{end}}{{end}}
 | 
					 | 
				
			||||||
		        </div>
 | 
					 | 
				
			||||||
		    </div>
 | 
					 | 
				
			||||||
		</div>
 | 
					 | 
				
			||||||
	</div>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
{{template "ng/base/footer" .}}
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user