mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-10 15:35:59 +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
|
||||
|
||||
class DashboardController extends DashboardControllerBase
|
||||
with IssuesService with RepositoryService with AccountService
|
||||
with IssuesService with PullRequestService with RepositoryService with AccountService
|
||||
with UsersAuthenticator
|
||||
|
||||
trait DashboardControllerBase extends ControllerBase {
|
||||
self: IssuesService with RepositoryService with UsersAuthenticator =>
|
||||
self: IssuesService with PullRequestService with RepositoryService with UsersAuthenticator =>
|
||||
|
||||
get("/dashboard/issues/repos")(usersOnly {
|
||||
searchIssues("all")
|
||||
@@ -22,6 +22,14 @@ trait DashboardControllerBase extends ControllerBase {
|
||||
searchIssues("created_by")
|
||||
})
|
||||
|
||||
get("/dashboard/pulls")(usersOnly {
|
||||
searchPullRequests("created_by")
|
||||
})
|
||||
|
||||
get("/dashboard/pulls/public")(usersOnly {
|
||||
searchPullRequests("all")
|
||||
})
|
||||
|
||||
private def searchIssues(filter: String) = {
|
||||
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(
|
||||
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,
|
||||
page,
|
||||
countIssue(condition.copy(state = "open"), filterUser, true, owner -> repoName),
|
||||
|
||||
@@ -18,13 +18,13 @@ trait PullRequestService { self: IssuesService =>
|
||||
} 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)
|
||||
.innerJoin(Issues).on { (t1, t2) => t1.byPrimaryKey(t2.userName, t2.repositoryName, t2.issueId) }
|
||||
.filter { case (t1, t2) =>
|
||||
(t2.closed is closed.bind) &&
|
||||
(t1.userName is repository.get._1, repository.isDefined) &&
|
||||
(t1.repositoryName is repository.get._2, repository.isDefined)
|
||||
(t1.userName is owner.bind) &&
|
||||
(t1.repositoryName is repository.get.bind, repository.isDefined)
|
||||
}
|
||||
.groupBy { case (t1, t2) => t2.openedUserName }
|
||||
.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">
|
||||
<li@if(active == ""){ class="active"}><a href="@path/">News Feed</a></li>
|
||||
@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>
|
||||
}
|
||||
</ul>
|
||||
|
||||
@@ -44,98 +44,7 @@
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
<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>
|
||||
@listparts(issues, page, openCount, closedCount, condition)
|
||||
</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