mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-03 03:55:58 +01:00
(refs #26) Implements the dashboard issue display.
This commit is contained in:
@@ -33,13 +33,21 @@ trait DashboardControllerBase extends ControllerBase {
|
|||||||
|
|
||||||
session.put(sessionKey, condition)
|
session.put(sessionKey, condition)
|
||||||
|
|
||||||
val repositories = getAccessibleRepositories(context.loginAccount, baseUrl)
|
val userName = context.loginAccount.get.userName
|
||||||
|
val repositories = getUserRepositories(userName, baseUrl).map(repo => repo.owner -> repo.name)
|
||||||
|
val filterUser = Map(filter -> userName)
|
||||||
|
val page = IssueSearchCondition.page(request)
|
||||||
//
|
//
|
||||||
dashboard.html.issues(
|
dashboard.html.issues(
|
||||||
issues.html.listparts(Nil, 0, 0, 0, condition),
|
issues.html.listparts(
|
||||||
0,
|
searchIssue(condition, filterUser, (page - 1) * IssueLimit, IssueLimit, repositories: _*),
|
||||||
0,
|
page,
|
||||||
0,
|
countIssue(condition.copy(state = "open"), filterUser, repositories: _*),
|
||||||
|
countIssue(condition.copy(state = "closed"), filterUser, repositories: _*),
|
||||||
|
condition),
|
||||||
|
countIssue(condition, Map.empty, repositories: _*),
|
||||||
|
countIssue(condition, Map("assigned" -> userName), repositories: _*),
|
||||||
|
countIssue(condition, Map("created_by" -> userName), repositories: _*),
|
||||||
repositories,
|
repositories,
|
||||||
condition,
|
condition,
|
||||||
filter)
|
filter)
|
||||||
|
|||||||
@@ -301,16 +301,10 @@ trait IssuesControllerBase extends ControllerBase {
|
|||||||
private def searchIssues(filter: String, repository: RepositoryService.RepositoryInfo) = {
|
private def searchIssues(filter: String, repository: RepositoryService.RepositoryInfo) = {
|
||||||
val owner = repository.owner
|
val owner = repository.owner
|
||||||
val repoName = repository.name
|
val repoName = repository.name
|
||||||
val userName = if(filter != "all") Some(params("userName")) else None
|
val filterUser = Map(filter -> params.getOrElse("userName", ""))
|
||||||
|
val page = IssueSearchCondition.page(request)
|
||||||
val sessionKey = s"${owner}/${repoName}/issues"
|
val sessionKey = s"${owner}/${repoName}/issues"
|
||||||
|
|
||||||
val page = try {
|
|
||||||
val i = params.getOrElse("page", "1").toInt
|
|
||||||
if(i <= 0) 1 else i
|
|
||||||
} catch {
|
|
||||||
case e: NumberFormatException => 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// retrieve search condition
|
// retrieve search condition
|
||||||
val condition = if(request.getQueryString == null){
|
val condition = if(request.getQueryString == null){
|
||||||
session.get(sessionKey).getOrElse(IssueSearchCondition()).asInstanceOf[IssueSearchCondition]
|
session.get(sessionKey).getOrElse(IssueSearchCondition()).asInstanceOf[IssueSearchCondition]
|
||||||
@@ -319,17 +313,17 @@ trait IssuesControllerBase extends ControllerBase {
|
|||||||
session.put(sessionKey, condition)
|
session.put(sessionKey, condition)
|
||||||
|
|
||||||
issues.html.list(
|
issues.html.list(
|
||||||
searchIssue(owner, repoName, condition, filter, userName, (page - 1) * IssueLimit, IssueLimit),
|
searchIssue(condition, filterUser, (page - 1) * IssueLimit, IssueLimit, owner -> repoName),
|
||||||
page,
|
page,
|
||||||
(getCollaborators(owner, repoName) :+ owner).sorted,
|
(getCollaborators(owner, repoName) :+ owner).sorted,
|
||||||
getMilestones(owner, repoName),
|
getMilestones(owner, repoName),
|
||||||
getLabels(owner, repoName),
|
getLabels(owner, repoName),
|
||||||
countIssue(owner, repoName, condition.copy(state = "open"), filter, userName),
|
countIssue(condition.copy(state = "open"), filterUser, owner -> repoName),
|
||||||
countIssue(owner, repoName, condition.copy(state = "closed"), filter, userName),
|
countIssue(condition.copy(state = "closed"), filterUser, owner -> repoName),
|
||||||
countIssue(owner, repoName, condition, "all", None),
|
countIssue(condition, Map.empty, owner -> repoName),
|
||||||
context.loginAccount.map(x => countIssue(owner, repoName, condition, "assigned", Some(x.userName))),
|
context.loginAccount.map(x => countIssue(condition, Map("assigned" -> x.userName), owner -> repoName)),
|
||||||
context.loginAccount.map(x => countIssue(owner, repoName, condition, "created_by", Some(x.userName))),
|
context.loginAccount.map(x => countIssue(condition, Map("created_by" -> x.userName), owner -> repoName)),
|
||||||
countIssueGroupByLabels(owner, repoName, condition, filter, userName),
|
countIssueGroupByLabels(owner, repoName, condition, filterUser),
|
||||||
condition,
|
condition,
|
||||||
filter,
|
filter,
|
||||||
repository,
|
repository,
|
||||||
|
|||||||
@@ -42,18 +42,16 @@ trait IssuesService {
|
|||||||
/**
|
/**
|
||||||
* Returns the count of the search result against issues.
|
* Returns the count of the search result against issues.
|
||||||
*
|
*
|
||||||
* @param owner the repository owner
|
|
||||||
* @param repository the repository name
|
|
||||||
* @param condition the search condition
|
* @param condition the search condition
|
||||||
* @param filter the filter type ("all", "assigned" or "created_by")
|
* @param filterUser the filter user name (key is "all", "assigned" or "created_by", value is the user name)
|
||||||
* @param userName the filter user name required for "assigned" and "created_by"
|
* @param repos Tuple of the repository owner and the repository name
|
||||||
* @return the count of the search result
|
* @return the count of the search result
|
||||||
*/
|
*/
|
||||||
def countIssue(owner: String, repository: String, condition: IssueSearchCondition, filter: String, userName: Option[String]): Int = {
|
def countIssue(condition: IssueSearchCondition, filterUser: Map[String, String], repos: (String, String)*): Int = {
|
||||||
// TODO It must be _.length instead of map (_.issueId) list).length.
|
// TODO It must be _.length instead of map (_.issueId) list).length.
|
||||||
// But it does not work on Slick 1.0.1 (worked on Slick 1.0.0).
|
// But it does not work on Slick 1.0.1 (worked on Slick 1.0.0).
|
||||||
// https://github.com/slick/slick/issues/170
|
// https://github.com/slick/slick/issues/170
|
||||||
(searchIssueQuery(owner, repository, condition, filter, userName) map (_.issueId) list).length
|
(searchIssueQuery(repos, condition, filterUser) map (_.issueId) list).length
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Returns the Map which contains issue count for each labels.
|
* Returns the Map which contains issue count for each labels.
|
||||||
@@ -61,14 +59,13 @@ trait IssuesService {
|
|||||||
* @param owner the repository owner
|
* @param owner the repository owner
|
||||||
* @param repository the repository name
|
* @param repository the repository name
|
||||||
* @param condition the search condition
|
* @param condition the search condition
|
||||||
* @param filter the filter type ("all", "assigned" or "created_by")
|
* @param filterUser the filter user name (key is "all", "assigned" or "created_by", value is the user name)
|
||||||
* @param userName the filter user name required for "assigned" and "created_by"
|
* @return the Map which contains issue count for each labels (key is label name, value is issue count)
|
||||||
* @return the Map which contains issue count for each labels (key is label name, value is issue count),
|
|
||||||
*/
|
*/
|
||||||
def countIssueGroupByLabels(owner: String, repository: String, condition: IssueSearchCondition,
|
def countIssueGroupByLabels(owner: String, repository: String, condition: IssueSearchCondition,
|
||||||
filter: String, userName: Option[String]): Map[String, Int] = {
|
filterUser: Map[String, String]): Map[String, Int] = {
|
||||||
|
|
||||||
searchIssueQuery(owner, repository, condition.copy(labels = Set.empty), filter, userName)
|
searchIssueQuery(Seq(owner -> repository), condition.copy(labels = Set.empty), filterUser)
|
||||||
.innerJoin(IssueLabels).on { (t1, t2) =>
|
.innerJoin(IssueLabels).on { (t1, t2) =>
|
||||||
t1.byIssue(t2.userName, t2.repositoryName, t2.issueId)
|
t1.byIssue(t2.userName, t2.repositoryName, t2.issueId)
|
||||||
}
|
}
|
||||||
@@ -87,20 +84,18 @@ trait IssuesService {
|
|||||||
/**
|
/**
|
||||||
* Returns the search result against issues.
|
* Returns the search result against issues.
|
||||||
*
|
*
|
||||||
* @param owner the repository owner
|
|
||||||
* @param repository the repository name
|
|
||||||
* @param condition the search condition
|
* @param condition the search condition
|
||||||
* @param filter the filter type ("all", "assigned" or "created_by")
|
* @param filterUser the filter user name (key is "all", "assigned" or "created_by", value is the user name)
|
||||||
* @param userName the filter user name required for "assigned" and "created_by"
|
|
||||||
* @param offset the offset for pagination
|
* @param offset the offset for pagination
|
||||||
* @param limit the limit for pagination
|
* @param limit the limit for pagination
|
||||||
|
* @param repos Tuple of the repository owner and the repository name
|
||||||
* @return the search result (list of tuples which contain issue, labels and comment count)
|
* @return the search result (list of tuples which contain issue, labels and comment count)
|
||||||
*/
|
*/
|
||||||
def searchIssue(owner: String, repository: String, condition: IssueSearchCondition,
|
def searchIssue(condition: IssueSearchCondition, filterUser: Map[String, String],
|
||||||
filter: String, userName: Option[String], offset: Int, limit: Int): List[(Issue, List[Label], Int)] = {
|
offset: Int, limit: Int, repos: (String, String)*): List[(Issue, List[Label], Int)] = {
|
||||||
|
|
||||||
// get issues and comment count and labels
|
// get issues and comment count and labels
|
||||||
searchIssueQuery(owner, repository, condition, filter, userName)
|
searchIssueQuery(repos, condition, filterUser)
|
||||||
.innerJoin(IssueOutline).on { (t1, t2) => t1.byIssue(t2.userName, t2.repositoryName, t2.issueId) }
|
.innerJoin(IssueOutline).on { (t1, t2) => t1.byIssue(t2.userName, t2.repositoryName, t2.issueId) }
|
||||||
.leftJoin (IssueLabels) .on { case ((t1, t2), t3) => t1.byIssue(t3.userName, t3.repositoryName, t3.issueId) }
|
.leftJoin (IssueLabels) .on { case ((t1, t2), t3) => t1.byIssue(t3.userName, t3.repositoryName, t3.issueId) }
|
||||||
.leftJoin (Labels) .on { case (((t1, t2), t3), t4) => t3.byLabel(t4.userName, t4.repositoryName, t4.labelId) }
|
.leftJoin (Labels) .on { case (((t1, t2), t3), t4) => t3.byLabel(t4.userName, t4.repositoryName, t4.labelId) }
|
||||||
@@ -136,14 +131,14 @@ trait IssuesService {
|
|||||||
/**
|
/**
|
||||||
* Assembles query for conditional issue searching.
|
* Assembles query for conditional issue searching.
|
||||||
*/
|
*/
|
||||||
private def searchIssueQuery(owner: String, repository: String, condition: IssueSearchCondition, filter: String, userName: Option[String]) =
|
private def searchIssueQuery(repos: Seq[(String, String)], condition: IssueSearchCondition, filterUser: Map[String, String]) =
|
||||||
Query(Issues) filter { t1 =>
|
Query(Issues) filter { t1 =>
|
||||||
(t1.byRepository(owner, repository)) &&
|
(repos.map { case (owner, repository) => t1.byRepository(owner, repository) } reduceLeft ( _ || _ ) ) &&
|
||||||
(t1.closed is (condition.state == "closed").bind) &&
|
(t1.closed is (condition.state == "closed").bind) &&
|
||||||
(t1.milestoneId is condition.milestoneId.get.get.bind, condition.milestoneId.flatten.isDefined) &&
|
(t1.milestoneId is condition.milestoneId.get.get.bind, condition.milestoneId.flatten.isDefined) &&
|
||||||
(t1.milestoneId isNull, condition.milestoneId == Some(None)) &&
|
(t1.milestoneId isNull, condition.milestoneId == Some(None)) &&
|
||||||
(t1.assignedUserName is userName.get.bind, filter == "assigned") &&
|
(t1.assignedUserName is filterUser("assigned").bind, filterUser.get("assigned").isDefined) &&
|
||||||
(t1.openedUserName is userName.get.bind, filter == "created_by") &&
|
(t1.openedUserName is filterUser("created_by").bind, filterUser.get("created_by").isDefined) &&
|
||||||
(IssueLabels filter { t2 =>
|
(IssueLabels filter { t2 =>
|
||||||
(t2.byIssue(t1.userName, t1.repositoryName, t1.issueId)) &&
|
(t2.byIssue(t1.userName, t1.repositoryName, t1.issueId)) &&
|
||||||
(t2.labelId in
|
(t2.labelId in
|
||||||
@@ -329,6 +324,13 @@ object IssuesService {
|
|||||||
param(request, "state", Seq("open", "closed")).getOrElse("open"),
|
param(request, "state", Seq("open", "closed")).getOrElse("open"),
|
||||||
param(request, "sort", Seq("created", "comments", "updated")).getOrElse("created"),
|
param(request, "sort", Seq("created", "comments", "updated")).getOrElse("created"),
|
||||||
param(request, "direction", Seq("asc", "desc")).getOrElse("desc"))
|
param(request, "direction", Seq("asc", "desc")).getOrElse("desc"))
|
||||||
|
|
||||||
|
def page(request: HttpServletRequest) = try {
|
||||||
|
val i = param(request, "page").getOrElse("1").toInt
|
||||||
|
if(i <= 0) 1 else i
|
||||||
|
} catch {
|
||||||
|
case e: NumberFormatException => 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
allCount: Int,
|
allCount: Int,
|
||||||
assignedCount: Int,
|
assignedCount: Int,
|
||||||
createdByCount: Int,
|
createdByCount: Int,
|
||||||
repositories: List[service.RepositoryService.RepositoryInfo],
|
repositories: List[(String, String)],
|
||||||
condition: service.IssuesService.IssueSearchCondition,
|
condition: service.IssuesService.IssueSearchCondition,
|
||||||
filter: String)(implicit context: app.Context)
|
filter: String)(implicit context: app.Context)
|
||||||
@import context._
|
@import context._
|
||||||
@@ -33,11 +33,11 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<hr/>
|
<hr/>
|
||||||
<ul class="nav nav-pills nav-stacked small">
|
<ul class="nav nav-pills nav-stacked small">
|
||||||
@repositories.map { repository =>
|
@repositories.map { case (owner, name) =>
|
||||||
<li>
|
<li>
|
||||||
<a href="@condition.copy(repo = Some(repository.owner + "/" + repository.name)).toURL">
|
<a href="@condition.copy(repo = Some(owner + "/" + name)).toURL">
|
||||||
<span class="count-right">0</span>
|
<span class="count-right">0</span>
|
||||||
@repository.owner/@repository.name
|
@owner/@name
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,7 +146,7 @@
|
|||||||
<input type="checkbox" value="@issue.issueId"/>
|
<input type="checkbox" value="@issue.issueId"/>
|
||||||
}
|
}
|
||||||
@if(repository.isEmpty){
|
@if(repository.isEmpty){
|
||||||
<a href="@path/@issue.userName/@issue.repositoryName">@issue.repositoryName</a> ・
|
<a href="@path/@issue.userName/@issue.repositoryName">@issue.repositoryName</a> ・
|
||||||
}
|
}
|
||||||
<a href="@path/@issue.userName/@issue.repositoryName/issues/@issue.issueId" class="issue-title">@issue.title</a>
|
<a href="@path/@issue.userName/@issue.repositoryName/issues/@issue.issueId" class="issue-title">@issue.title</a>
|
||||||
@labels.map { label =>
|
@labels.map { label =>
|
||||||
|
|||||||
Reference in New Issue
Block a user