mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-11 07:55:55 +01:00
(refs #2)Implementing 'Pull Requests' tab in the dashboard.
This commit is contained in:
@@ -4,11 +4,11 @@ import service._
|
|||||||
import util.UsersAuthenticator
|
import util.UsersAuthenticator
|
||||||
|
|
||||||
class DashboardController extends DashboardControllerBase
|
class DashboardController extends DashboardControllerBase
|
||||||
with IssuesService with RepositoryService with AccountService
|
with IssuesService with PullRequestService with RepositoryService with AccountService
|
||||||
with UsersAuthenticator
|
with UsersAuthenticator
|
||||||
|
|
||||||
trait DashboardControllerBase extends ControllerBase {
|
trait DashboardControllerBase extends ControllerBase {
|
||||||
self: IssuesService with RepositoryService with UsersAuthenticator =>
|
self: IssuesService with PullRequestService with RepositoryService with UsersAuthenticator =>
|
||||||
|
|
||||||
get("/dashboard/issues/repos")(usersOnly {
|
get("/dashboard/issues/repos")(usersOnly {
|
||||||
searchIssues("all")
|
searchIssues("all")
|
||||||
@@ -22,6 +22,14 @@ trait DashboardControllerBase extends ControllerBase {
|
|||||||
searchIssues("created_by")
|
searchIssues("created_by")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
get("/dashboard/pulls")(usersOnly {
|
||||||
|
searchPullRequests("created_by")
|
||||||
|
})
|
||||||
|
|
||||||
|
get("/dashboard/pulls/public")(usersOnly {
|
||||||
|
searchPullRequests("all")
|
||||||
|
})
|
||||||
|
|
||||||
private def searchIssues(filter: String) = {
|
private def searchIssues(filter: String) = {
|
||||||
import IssuesService._
|
import IssuesService._
|
||||||
|
|
||||||
@@ -54,4 +62,36 @@ trait DashboardControllerBase extends ControllerBase {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def searchPullRequests(filter: String) = {
|
||||||
|
import IssuesService._
|
||||||
|
import PullRequestService._
|
||||||
|
|
||||||
|
// condition
|
||||||
|
val sessionKey = "dashboard/pulls"
|
||||||
|
val condition = if(request.getQueryString == null)
|
||||||
|
session.get(sessionKey).getOrElse(IssueSearchCondition()).asInstanceOf[IssueSearchCondition]
|
||||||
|
else IssueSearchCondition(request)
|
||||||
|
|
||||||
|
session.put(sessionKey, condition)
|
||||||
|
|
||||||
|
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.pulls(
|
||||||
|
pulls.html.listparts(
|
||||||
|
searchIssue(condition, filterUser, true, (page - 1) * PullRequestLimit, PullRequestLimit, repositories: _*),
|
||||||
|
page,
|
||||||
|
countIssue(condition.copy(state = "open"), filterUser, false, repositories: _*),
|
||||||
|
countIssue(condition.copy(state = "closed"), filterUser, false, repositories: _*),
|
||||||
|
condition),
|
||||||
|
countIssue(condition, Map.empty, true, repositories: _*),
|
||||||
|
getPullRequestCount(condition.state == "closed", userName, None),
|
||||||
|
condition,
|
||||||
|
filter)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -386,7 +386,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
|||||||
|
|
||||||
pulls.html.list(
|
pulls.html.list(
|
||||||
searchIssue(condition, filterUser, true, (page - 1) * PullRequestLimit, PullRequestLimit, owner -> repoName),
|
searchIssue(condition, filterUser, true, (page - 1) * PullRequestLimit, PullRequestLimit, owner -> repoName),
|
||||||
getPullRequestCount(condition.state == "closed", Some(owner, repoName)),
|
getPullRequestCount(condition.state == "closed", owner, Some(repoName)),
|
||||||
userName,
|
userName,
|
||||||
page,
|
page,
|
||||||
countIssue(condition.copy(state = "open"), filterUser, true, owner -> repoName),
|
countIssue(condition.copy(state = "open"), filterUser, true, owner -> repoName),
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ trait PullRequestService { self: IssuesService =>
|
|||||||
} else None
|
} else None
|
||||||
}
|
}
|
||||||
|
|
||||||
def getPullRequestCount(closed: Boolean, repository: Option[(String, String)]): List[PullRequestCount] =
|
def getPullRequestCount(closed: Boolean, owner: String, repository: Option[String]): List[PullRequestCount] =
|
||||||
Query(PullRequests)
|
Query(PullRequests)
|
||||||
.innerJoin(Issues).on { (t1, t2) => t1.byPrimaryKey(t2.userName, t2.repositoryName, t2.issueId) }
|
.innerJoin(Issues).on { (t1, t2) => t1.byPrimaryKey(t2.userName, t2.repositoryName, t2.issueId) }
|
||||||
.filter { case (t1, t2) =>
|
.filter { case (t1, t2) =>
|
||||||
(t2.closed is closed.bind) &&
|
(t2.closed is closed.bind) &&
|
||||||
(t1.userName is repository.get._1, repository.isDefined) &&
|
(t1.userName is owner.bind) &&
|
||||||
(t1.repositoryName is repository.get._2, repository.isDefined)
|
(t1.repositoryName is repository.get.bind, repository.isDefined)
|
||||||
}
|
}
|
||||||
.groupBy { case (t1, t2) => t2.openedUserName }
|
.groupBy { case (t1, t2) => t2.openedUserName }
|
||||||
.map { case (userName, t) => userName ~ t.length }
|
.map { case (userName, t) => userName ~ t.length }
|
||||||
|
|||||||
42
src/main/twirl/dashboard/pulls.scala.html
Normal file
42
src/main/twirl/dashboard/pulls.scala.html
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
@(listparts: twirl.api.Html,
|
||||||
|
allCount: Int,
|
||||||
|
counts: List[service.PullRequestService.PullRequestCount],
|
||||||
|
condition: service.IssuesService.IssueSearchCondition,
|
||||||
|
filter: String)(implicit context: app.Context)
|
||||||
|
@import context._
|
||||||
|
@import view.helpers._
|
||||||
|
@html.main("Your Issues"){
|
||||||
|
@dashboard.html.tab("pulls")
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="span3">
|
||||||
|
<ul class="nav nav-pills nav-stacked">
|
||||||
|
<li@if(filter == "all"){ class="active"}>
|
||||||
|
<a href="@path/dashboard/pulls/owned@condition.toURL">
|
||||||
|
<span class="count-right">@counts.find(_.userName == loginAccount.get.userName).map(_.count)</span>
|
||||||
|
Yours
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="@path/dashboard/pulls/public@condition.toURL">
|
||||||
|
<span class="count-right">@allCount</span>
|
||||||
|
Public
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<hr/>
|
||||||
|
<ul class="nav nav-pills nav-stacked small">
|
||||||
|
@counts.map { user =>
|
||||||
|
@if(user.userName != loginAccount.get.userName){
|
||||||
|
<li>
|
||||||
|
<a href="@path/dashboard/@user.userName@condition.toURL">
|
||||||
|
<span class="count-right">@user.count</span>
|
||||||
|
@user.userName
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
@listparts
|
||||||
|
</div>
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
<ul class="nav nav-tabs">
|
<ul class="nav nav-tabs">
|
||||||
<li@if(active == ""){ class="active"}><a href="@path/">News Feed</a></li>
|
<li@if(active == ""){ class="active"}><a href="@path/">News Feed</a></li>
|
||||||
@if(loginAccount.isDefined){
|
@if(loginAccount.isDefined){
|
||||||
|
<li@if(active == "pulls" ){ class="active"}><a href="@path/dashboard/pulls">Pull Requests</a></li>
|
||||||
<li@if(active == "issues"){ class="active"}><a href="@path/dashboard/issues/repos">Issues</a></li>
|
<li@if(active == "issues"){ class="active"}><a href="@path/dashboard/issues/repos">Issues</a></li>
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -44,98 +44,7 @@
|
|||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="span9">
|
@listparts(issues, page, openCount, closedCount, condition)
|
||||||
@if(hasWritePermission){
|
|
||||||
<div class="pull-right">
|
|
||||||
@helper.html.paginator(page, (if(condition.state == "open") openCount else closedCount), service.PullRequestService.PullRequestLimit, 7, condition.toURL)
|
|
||||||
<a href="@url(repository)/compare" class="btn btn-success">New pull request</a>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<div class="btn-group">
|
|
||||||
<a class="btn@if(condition.state == "open"){ active}" href="@condition.copy(state = "open").toURL">@openCount Open</a>
|
|
||||||
<a class="btn@if(condition.state == "closed"){ active}" href="@condition.copy(state = "closed").toURL">@closedCount Closed</a>
|
|
||||||
</div>
|
|
||||||
<div class="btn-group">
|
|
||||||
<button class="btn dropdown-toggle" data-toggle="dropdown">
|
|
||||||
Sort:
|
|
||||||
<strong>
|
|
||||||
@if(condition.sort == "created" && condition.direction == "desc"){ Newest }
|
|
||||||
@if(condition.sort == "created" && condition.direction == "asc" ){ Oldest }
|
|
||||||
@if(condition.sort == "comments" && condition.direction == "desc"){ Most commented }
|
|
||||||
@if(condition.sort == "comments" && condition.direction == "asc" ){ Least commented }
|
|
||||||
@if(condition.sort == "updated" && condition.direction == "desc"){ Recently updated }
|
|
||||||
@if(condition.sort == "updated" && condition.direction == "asc" ){ Least recently updated }
|
|
||||||
</strong>
|
|
||||||
<span class="caret"></span>
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li>
|
|
||||||
<a href="@condition.copy(sort="created", direction="desc").toURL">
|
|
||||||
@helper.html.checkicon(condition.sort == "created" && condition.direction == "desc") Newest
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="@condition.copy(sort="created", direction="asc" ).toURL">
|
|
||||||
@helper.html.checkicon(condition.sort == "created" && condition.direction == "asc") Oldest
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="@condition.copy(sort="comments", direction="desc").toURL">
|
|
||||||
@helper.html.checkicon(condition.sort == "comments" && condition.direction == "desc") Most commented
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="@condition.copy(sort="comments", direction="asc" ).toURL">
|
|
||||||
@helper.html.checkicon(condition.sort == "comments" && condition.direction == "asc") Least commented
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="@condition.copy(sort="updated", direction="desc").toURL">
|
|
||||||
@helper.html.checkicon(condition.sort == "updated" && condition.direction == "desc") Recently updated
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="@condition.copy(sort="updated", direction="asc" ).toURL">
|
|
||||||
@helper.html.checkicon(condition.sort == "updated" && condition.direction == "asc") Least recently updated
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<table class="table table-bordered table-hover table-issues">
|
|
||||||
@if(issues.isEmpty){
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 20px; background-color: #eee; text-align: center;">
|
|
||||||
No pull requests to show.
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
@issues.map { case (issue, labels, commentCount) =>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<img src="@assets/common/images/pullreq-@(if(issue.closed) "closed" else "open").png"/>
|
|
||||||
<a href="@path/@issue.userName/@issue.repositoryName/pull/@issue.issueId" class="issue-title">@issue.title</a>
|
|
||||||
<span class="pull-right muted">#@issue.issueId</span>
|
|
||||||
<div style="margin-left: 20px;">
|
|
||||||
@issue.content.map { content =>
|
|
||||||
@cut(content, 90)
|
|
||||||
}.getOrElse {
|
|
||||||
<span class="muted">No description available</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div class="small muted" style="margin-left: 20px;">
|
|
||||||
@avatar(issue.openedUserName, 20) by <a href="@url(issue.openedUserName)" class="username">@issue.openedUserName</a> @datetime(issue.registeredDate)
|
|
||||||
@if(commentCount > 0){
|
|
||||||
<i class="icon-comment"></i><a href="@path/@issue.userName/@issue.repositoryName/issues/@issue.issueId" class="issue-comment-count">@commentCount @plural(commentCount, "comment")</a>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
</table>
|
|
||||||
<div class="pull-right">
|
|
||||||
@helper.html.paginator(page, (if(condition.state == "open") openCount else closedCount), service.PullRequestService.PullRequestLimit, 10, condition.toURL)
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
101
src/main/twirl/pulls/listparts.scala.html
Normal file
101
src/main/twirl/pulls/listparts.scala.html
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
@(issues: List[(model.Issue, List[model.Label], Int)],
|
||||||
|
page: Int,
|
||||||
|
openCount: Int,
|
||||||
|
closedCount: Int,
|
||||||
|
condition: service.IssuesService.IssueSearchCondition)(implicit context: app.Context)
|
||||||
|
@import context._
|
||||||
|
@import view.helpers._
|
||||||
|
<div class="span9">
|
||||||
|
@*
|
||||||
|
@if(hasWritePermission){
|
||||||
|
<div class="pull-right">
|
||||||
|
@helper.html.paginator(page, (if(condition.state == "open") openCount else closedCount), service.PullRequestService.PullRequestLimit, 7, condition.toURL)
|
||||||
|
<a href="@url(repository)/compare" class="btn btn-success">New pull request</a>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
*@
|
||||||
|
<div class="btn-group">
|
||||||
|
<a class="btn@if(condition.state == "open"){ active}" href="@condition.copy(state = "open").toURL">@openCount Open</a>
|
||||||
|
<a class="btn@if(condition.state == "closed"){ active}" href="@condition.copy(state = "closed").toURL">@closedCount Closed</a>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group">
|
||||||
|
<button class="btn dropdown-toggle" data-toggle="dropdown">
|
||||||
|
Sort:
|
||||||
|
<strong>
|
||||||
|
@if(condition.sort == "created" && condition.direction == "desc"){ Newest }
|
||||||
|
@if(condition.sort == "created" && condition.direction == "asc" ){ Oldest }
|
||||||
|
@if(condition.sort == "comments" && condition.direction == "desc"){ Most commented }
|
||||||
|
@if(condition.sort == "comments" && condition.direction == "asc" ){ Least commented }
|
||||||
|
@if(condition.sort == "updated" && condition.direction == "desc"){ Recently updated }
|
||||||
|
@if(condition.sort == "updated" && condition.direction == "asc" ){ Least recently updated }
|
||||||
|
</strong>
|
||||||
|
<span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li>
|
||||||
|
<a href="@condition.copy(sort="created", direction="desc").toURL">
|
||||||
|
@helper.html.checkicon(condition.sort == "created" && condition.direction == "desc") Newest
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="@condition.copy(sort="created", direction="asc" ).toURL">
|
||||||
|
@helper.html.checkicon(condition.sort == "created" && condition.direction == "asc") Oldest
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="@condition.copy(sort="comments", direction="desc").toURL">
|
||||||
|
@helper.html.checkicon(condition.sort == "comments" && condition.direction == "desc") Most commented
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="@condition.copy(sort="comments", direction="asc" ).toURL">
|
||||||
|
@helper.html.checkicon(condition.sort == "comments" && condition.direction == "asc") Least commented
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="@condition.copy(sort="updated", direction="desc").toURL">
|
||||||
|
@helper.html.checkicon(condition.sort == "updated" && condition.direction == "desc") Recently updated
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="@condition.copy(sort="updated", direction="asc" ).toURL">
|
||||||
|
@helper.html.checkicon(condition.sort == "updated" && condition.direction == "asc") Least recently updated
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<table class="table table-bordered table-hover table-issues">
|
||||||
|
@if(issues.isEmpty){
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 20px; background-color: #eee; text-align: center;">
|
||||||
|
No pull requests to show.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
@issues.map { case (issue, labels, commentCount) =>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="@assets/common/images/pullreq-@(if(issue.closed) "closed" else "open").png"/>
|
||||||
|
<a href="@path/@issue.userName/@issue.repositoryName/pull/@issue.issueId" class="issue-title">@issue.title</a>
|
||||||
|
<span class="pull-right muted">#@issue.issueId</span>
|
||||||
|
<div style="margin-left: 20px;">
|
||||||
|
@issue.content.map { content =>
|
||||||
|
@cut(content, 90)
|
||||||
|
}.getOrElse {
|
||||||
|
<span class="muted">No description available</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="small muted" style="margin-left: 20px;">
|
||||||
|
@avatar(issue.openedUserName, 20) by <a href="@url(issue.openedUserName)" class="username">@issue.openedUserName</a> @datetime(issue.registeredDate)
|
||||||
|
@if(commentCount > 0){
|
||||||
|
<i class="icon-comment"></i><a href="@path/@issue.userName/@issue.repositoryName/issues/@issue.issueId" class="issue-comment-count">@commentCount @plural(commentCount, "comment")</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
<div class="pull-right">
|
||||||
|
@helper.html.paginator(page, (if(condition.state == "open") openCount else closedCount), service.PullRequestService.PullRequestLimit, 10, condition.toURL)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Reference in New Issue
Block a user