(refs #2)Implementing 'Pull Requests' tab in the dashboard.

This commit is contained in:
takezoe
2013-08-06 22:04:09 +09:00
parent 50655d1ac2
commit 908931b9ed
7 changed files with 191 additions and 98 deletions

View File

@@ -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)
}
} }

View File

@@ -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),

View File

@@ -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 }

View 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>
}

View File

@@ -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>

View File

@@ -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)&nbsp;
@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>
} }

View 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)&nbsp;
@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>