(refs #529)Visibility filter

This commit is contained in:
Naoki Takezoe
2014-11-01 03:05:52 +09:00
parent 13c206d068
commit e6e3786b47
6 changed files with 177 additions and 140 deletions

View File

@@ -74,29 +74,16 @@ trait DashboardControllerBase extends ControllerBase {
val userName = context.loginAccount.get.userName val userName = context.loginAccount.get.userName
val allRepos = getAllRepositories(userName) val allRepos = getAllRepositories(userName)
val userRepos = getUserRepositories(userName, context.baseUrl, true).map(repo => repo.owner -> repo.name)
val filterUser = Map(filter -> userName) val filterUser = Map(filter -> userName)
val page = IssueSearchCondition.page(request) val page = IssueSearchCondition.page(request)
val counts = countIssueGroupByRepository(
IssueSearchCondition().copy(state = condition.state), filterUser, true, userRepos: _*)
dashboard.html.pulls( dashboard.html.pulls(
dashboard.html.pullslist(
searchIssue(condition, filterUser, true, (page - 1) * PullRequestLimit, PullRequestLimit, allRepos: _*), searchIssue(condition, filterUser, true, (page - 1) * PullRequestLimit, PullRequestLimit, allRepos: _*),
page, page,
countIssue(condition.copy(state = "open" ), filterUser, true, allRepos: _*), countIssue(condition.copy(state = "open" ), filterUser, true, allRepos: _*),
countIssue(condition.copy(state = "closed"), filterUser, true, allRepos: _*), countIssue(condition.copy(state = "closed"), filterUser, true, allRepos: _*),
condition, condition,
None,
false),
getAllPullRequestCountGroupByUser(condition.state == "closed", userName),
userRepos.map { case (userName, repoName) =>
(userName, repoName, counts.find { x => x._1 == userName && x._2 == repoName }.map(_._3).getOrElse(0))
}.sortBy(_._3).reverse,
condition,
filter) filter)
} }

View File

@@ -77,28 +77,29 @@ trait IssuesService {
} }
.toMap .toMap
} }
/**
* Returns list which contains issue count for each repository. // /**
* If the issue does not exist, its repository is not included in the result. // * Returns list which contains issue count for each repository.
* // * If the issue does not exist, its repository is not included in the result.
* @param condition the search condition // *
* @param onlyPullRequest if true then returns only pull request, false then returns both of issue and pull request. // * @param condition the search condition
* @param repos Tuple of the repository owner and the repository name // * @param onlyPullRequest if true then returns only pull request, false then returns both of issue and pull request.
* @return list which contains issue count for each repository // * @param repos Tuple of the repository owner and the repository name
*/ // * @return list which contains issue count for each repository
def countIssueGroupByRepository( // */
condition: IssueSearchCondition, filterUser: Map[String, String], onlyPullRequest: Boolean, // def countIssueGroupByRepository(
repos: (String, String)*)(implicit s: Session): List[(String, String, Int)] = { // condition: IssueSearchCondition, filterUser: Map[String, String], onlyPullRequest: Boolean,
searchIssueQuery(repos, condition.copy(repo = None), filterUser, onlyPullRequest) // repos: (String, String)*)(implicit s: Session): List[(String, String, Int)] = {
.groupBy { t => // searchIssueQuery(repos, condition.copy(repo = None), filterUser, onlyPullRequest)
t.userName -> t.repositoryName // .groupBy { t =>
} // t.userName -> t.repositoryName
.map { case (repo, t) => // }
(repo._1, repo._2, t.length) // .map { case (repo, t) =>
} // (repo._1, repo._2, t.length)
.sortBy(_._3 desc) // }
.list // .sortBy(_._3 desc)
} // .list
// }
/** /**
* Returns the search result against issues. * Returns the search result against issues.
@@ -181,7 +182,11 @@ trait IssuesService {
(t3.byRepository(t1.userName, t1.repositoryName)) && (t3.byRepository(t1.userName, t1.repositoryName)) &&
(t3.labelName inSetBind condition.labels) (t3.labelName inSetBind condition.labels)
} map(_.labelId))) } map(_.labelId)))
} exists, condition.labels.nonEmpty) } exists, condition.labels.nonEmpty) &&
(Repositories filter { t3 =>
(t3.byRepository(t1.userName, t1.repositoryName)) &&
(t3.isPrivate === (condition.visibility == Some("private")).bind)
} exists, condition.visibility.nonEmpty)
} }
def createIssue(owner: String, repository: String, loginUser: String, title: String, content: Option[String], def createIssue(owner: String, repository: String, loginUser: String, title: String, content: Option[String],
@@ -343,11 +348,12 @@ object IssuesService {
repo: Option[String] = None, repo: Option[String] = None,
state: String = "open", state: String = "open",
sort: String = "created", sort: String = "created",
direction: String = "desc"){ direction: String = "desc",
visibility: Option[String] = None){
def isEmpty: Boolean = { def isEmpty: Boolean = {
labels.isEmpty && milestoneId.isEmpty && author.isEmpty && assigned.isEmpty && labels.isEmpty && milestoneId.isEmpty && author.isEmpty && assigned.isEmpty &&
state == "open" && sort == "created" && direction == "desc" state == "open" && sort == "created" && direction == "desc" && visibility.isEmpty
} }
def nonEmpty: Boolean = !isEmpty def nonEmpty: Boolean = !isEmpty
@@ -364,7 +370,9 @@ object IssuesService {
repo.map("for=" + urlEncode(_)), repo.map("for=" + urlEncode(_)),
Some("state=" + urlEncode(state)), Some("state=" + urlEncode(state)),
Some("sort=" + urlEncode(sort)), Some("sort=" + urlEncode(sort)),
Some("direction=" + urlEncode(direction))).flatten.mkString("&") Some("direction=" + urlEncode(direction)),
visibility.map(x => "visibility=" + urlEncode(x))
).flatten.mkString("&")
} }
@@ -387,7 +395,9 @@ object IssuesService {
param(request, "for"), param(request, "for"),
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"),
param(request, "visibility")
)
def page(request: HttpServletRequest) = try { def page(request: HttpServletRequest) = try {
val i = param(request, "page").getOrElse("1").toInt val i = param(request, "page").getOrElse("1").toInt

View File

@@ -36,23 +36,23 @@ trait PullRequestService { self: IssuesService =>
.list .list
.map { x => PullRequestCount(x._1, x._2) } .map { x => PullRequestCount(x._1, x._2) }
def getAllPullRequestCountGroupByUser(closed: Boolean, userName: String)(implicit s: Session): List[PullRequestCount] = // def getAllPullRequestCountGroupByUser(closed: Boolean, userName: String)(implicit s: Session): List[PullRequestCount] =
PullRequests // 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) }
.innerJoin(Repositories).on { case ((t1, t2), t3) => t2.byRepository(t3.userName, t3.repositoryName) } // .innerJoin(Repositories).on { case ((t1, t2), t3) => t2.byRepository(t3.userName, t3.repositoryName) }
.filter { case ((t1, t2), t3) => // .filter { case ((t1, t2), t3) =>
(t2.closed === closed.bind) && // (t2.closed === closed.bind) &&
( // (
(t3.isPrivate === false.bind) || // (t3.isPrivate === false.bind) ||
(t3.userName === userName.bind) || // (t3.userName === userName.bind) ||
(Collaborators.filter { t4 => t4.byRepository(t3.userName, t3.repositoryName) && (t4.collaboratorName === userName.bind)} exists) // (Collaborators.filter { t4 => t4.byRepository(t3.userName, t3.repositoryName) && (t4.collaboratorName === userName.bind)} exists)
) // )
} // }
.groupBy { case ((t1, t2), t3) => t2.openedUserName } // .groupBy { case ((t1, t2), t3) => t2.openedUserName }
.map { case (userName, t) => userName -> t.length } // .map { case (userName, t) => userName -> t.length }
.sortBy(_._2 desc) // .sortBy(_._2 desc)
.list // .list
.map { x => PullRequestCount(x._1, x._2) } // .map { x => PullRequestCount(x._1, x._2) }
def createPullRequest(originUserName: String, originRepositoryName: String, issueId: Int, def createPullRequest(originUserName: String, originRepositoryName: String, issueId: Int,
originBranch: String, requestUserName: String, requestRepositoryName: String, requestBranch: String, originBranch: String, requestUserName: String, requestRepositoryName: String, requestBranch: String,

View File

@@ -29,7 +29,18 @@
</span> </span>
<div class="pull-right" id="table-issues-control"> <div class="pull-right" id="table-issues-control">
@helper.html.dropdown("Visibility", flat = true){ @helper.html.dropdown("Visibility", flat = true){
<li>TODO</li> <li>
<a href="@(condition.copy(visibility = (if(condition.visibility == Some("private")) None else Some("private"))).toURL)">
@helper.html.checkicon(condition.visibility == Some("private"))
Private repository only
</a>
</li>
<li>
<a href="@(condition.copy(visibility = (if(condition.visibility == Some("public")) None else Some("public"))).toURL)">
@helper.html.checkicon(condition.visibility == Some("public"))
Public repository only
</a>
</li>
} }
@helper.html.dropdown("Organization", flat = true){ @helper.html.dropdown("Organization", flat = true){
<li>TODO</li> <li>TODO</li>

View File

@@ -1,42 +1,14 @@
@(listparts: play.twirl.api.Html, @(issues: List[service.IssuesService.IssueInfo],
counts: List[service.PullRequestService.PullRequestCount], page: Int,
repositories: List[(String, String, Int)], openCount: Int,
closedCount: Int,
condition: service.IssuesService.IssueSearchCondition, condition: service.IssuesService.IssueSearchCondition,
filter: String)(implicit context: app.Context) filter: String)(implicit context: app.Context)
@import context._ @import context._
@import view.helpers._ @import view.helpers._
@html.main("Your Issues"){ @html.main("Pull Requests"){
<div class="container"> <div class="container">
@dashboard.html.tab("pulls") @dashboard.html.tab("pulls")
<div class="row-fluid"> @issueslist(issues, page, openCount, closedCount, condition, filter)
<div class="span3">
<ul class="nav nav-pills nav-stacked">
<li@if(filter == "created_by"){ class="active"}>
<a href="@path/dashboard/pulls/owned@condition.toURL">
<span class="count-right">@counts.find(_.userName == loginAccount.get.userName).map(_.count).getOrElse(0)</span>
Yours
</a>
</li>
<li@if(filter == "not_created_by"){ class="active"}>
<a href="@path/dashboard/pulls/public@condition.toURL">
<span class="count-right">@counts.filter(_.userName != loginAccount.get.userName).map(_.count).sum</span>
Public
</a>
</li>
</ul>
<hr/>
<ul class="nav nav-pills nav-stacked small">
@repositories.map { case (owner, name, count) =>
<li@if(condition.repo == Some(owner + "/" + name)){ class="active"}>
<a href="@path/dashboard/pulls/for/@owner/@name">
<span class="count-right">@count</span>
@owner/@name
</a>
</li>
}
</ul>
</div>
@listparts
</div>
</div> </div>
} }

View File

@@ -3,20 +3,19 @@
openCount: Int, openCount: Int,
closedCount: Int, closedCount: Int,
condition: service.IssuesService.IssueSearchCondition, condition: service.IssuesService.IssueSearchCondition,
repository: Option[service.RepositoryService.RepositoryInfo], filter: String)(implicit context: app.Context)
hasWritePermission: Boolean)(implicit context: app.Context)
@import context._ @import context._
@import view.helpers._ @import view.helpers._
@import service.IssuesService.IssueInfo @import service.IssuesService.IssueInfo
<ul class="nav nav-pills-group pull-left fill-width">
<li class="@if(filter == "created_by"){active} first"><a href="@path/dashboard/pulls/created_by@condition.toURL">Created</a></li>
<li class="@if(filter == "assigned"){active} last"><a href="@path/dashboard/pulls/assigned@condition.toURL">Assigned</a></li>
@*
<li class="last"><a href="#">Mentioned</a></li>
*@
</ul>
@*
<div class="span9"> <div class="span9">
@repository.map { repository =>
@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-small btn-success">New pull request</a>
</div>
}
}
<div class="btn-group"> <div class="btn-group">
<a class="btn btn-small@if(condition.state == "open"){ active}" href="@condition.copy(state = "open").toURL">@openCount Open</a> <a class="btn btn-small@if(condition.state == "open"){ active}" href="@condition.copy(state = "open").toURL">@openCount Open</a>
<a class="btn btn-small@if(condition.state == "closed"){ active}" href="@condition.copy(state = "closed").toURL">@closedCount Closed</a> <a class="btn btn-small@if(condition.state == "closed"){ active}" href="@condition.copy(state = "closed").toURL">@closedCount Closed</a>
@@ -64,14 +63,73 @@
</a> </a>
</li> </li>
} }
*@
<table class="table table-bordered table-hover table-issues"> <table class="table table-bordered table-hover table-issues">
@if(issues.isEmpty){
<tr> <tr>
<td style="padding: 20px; background-color: #eee; text-align: center;"> <th style="background-color: #eee;">
No pull requests to show. <span class="small">
</td> <a class="button-link@if(condition.state == "open"){ selected}" href="@condition.copy(state = "open").toURL">
</tr> <img src="@assets/common/images/status-open@(if(condition.state == "open"){"-active"}).png"/>
@openCount Open
</a>&nbsp;&nbsp;
<a class="button-link@if(condition.state == "closed"){ selected}" href="@condition.copy(state = "closed").toURL">
<img src="@assets/common/images/status-closed@(if(condition.state == "closed"){"-active"}).png"/>
@closedCount Closed
</a>
</span>
<div class="pull-right" id="table-issues-control">
@helper.html.dropdown("Visibility", flat = true){
<li>
<a href="@(condition.copy(visibility = (if(condition.visibility == Some("private")) None else Some("private"))).toURL)">
@helper.html.checkicon(condition.visibility == Some("private"))
Private repository only
</a>
</li>
<li>
<a href="@(condition.copy(visibility = (if(condition.visibility == Some("public")) None else Some("public"))).toURL)">
@helper.html.checkicon(condition.visibility == Some("public"))
Public repository only
</a>
</li>
} }
@helper.html.dropdown("Organization", flat = true){
<li>TODO</li>
}
@helper.html.dropdown("Sort", flat = true){
<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>
}
</div>
</th>
</tr>
@issues.map { case IssueInfo(issue, labels, milestone, commentCount) => @issues.map { case IssueInfo(issue, labels, milestone, commentCount) =>
<tr> <tr>
<td> <td>
@@ -98,4 +156,3 @@
<div class="pull-right"> <div class="pull-right">
@helper.html.paginator(page, (if(condition.state == "open") openCount else closedCount), service.PullRequestService.PullRequestLimit, 10, condition.toURL) @helper.html.paginator(page, (if(condition.state == "open") openCount else closedCount), service.PullRequestService.PullRequestLimit, 10, condition.toURL)
</div> </div>
</div>