(refs #508)Basic filter box implementation

This commit is contained in:
Naoki Takezoe
2014-11-11 12:07:22 +09:00
parent 65a1ca7146
commit bc0b11b60a
4 changed files with 555 additions and 493 deletions

View File

@@ -9,7 +9,6 @@ import util.Implicits._
import util.ControlUtil._ import util.ControlUtil._
import org.scalatra.Ok import org.scalatra.Ok
import model.Issue import model.Issue
import plugin.PluginSystem
class IssuesController extends IssuesControllerBase class IssuesController extends IssuesControllerBase
with IssuesService with RepositoryService with AccountService with LabelsService with MilestonesService with ActivityService with IssuesService with RepositoryService with AccountService with LabelsService with MilestonesService with ActivityService
@@ -50,7 +49,12 @@ trait IssuesControllerBase extends ControllerBase {
)(IssueStateForm.apply) )(IssueStateForm.apply)
get("/:owner/:repository/issues")(referrersOnly { repository => get("/:owner/:repository/issues")(referrersOnly { repository =>
searchIssues(repository) val q = request.getParameter("q")
if(Option(q).exists(_.contains("is:pr"))){
redirect(s"/${repository.owner}/${repository.name}/pulls?q=" + StringUtil.urlEncode(q))
} else {
searchIssues(repository)
}
}) })
get("/:owner/:repository/issues/:id")(referrersOnly { repository => get("/:owner/:repository/issues/:id")(referrersOnly { repository =>
@@ -390,7 +394,14 @@ trait IssuesControllerBase extends ControllerBase {
// retrieve search condition // retrieve search condition
val condition = session.putAndGet(sessionKey, val condition = session.putAndGet(sessionKey,
if(request.hasQueryString) IssueSearchCondition(request) if(request.hasQueryString){
val q = request.getParameter("q")
if(q == null){
IssueSearchCondition(request)
} else {
IssueSearchCondition(q, getMilestones(owner, repoName).map(x => (x.title, x.milestoneId)).toMap)
}
}
else session.getAs[IssueSearchCondition](sessionKey).getOrElse(IssueSearchCondition()) else session.getAs[IssueSearchCondition](sessionKey).getOrElse(IssueSearchCondition())
) )

View File

@@ -1,6 +1,6 @@
package app package app
import util.{LockUtil, CollaboratorsAuthenticator, JGitUtil, ReferrerAuthenticator, Notifier, Keys} import util._
import util.Directory._ import util.Directory._
import util.Implicits._ import util.Implicits._
import util.ControlUtil._ import util.ControlUtil._
@@ -18,6 +18,9 @@ import org.slf4j.LoggerFactory
import org.eclipse.jgit.merge.MergeStrategy import org.eclipse.jgit.merge.MergeStrategy
import org.eclipse.jgit.errors.NoMergeBaseException import org.eclipse.jgit.errors.NoMergeBaseException
import service.WebHookService.WebHookPayload import service.WebHookService.WebHookPayload
import util.JGitUtil.DiffInfo
import scala.Some
import util.JGitUtil.CommitInfo
class PullRequestsController extends PullRequestsControllerBase class PullRequestsController extends PullRequestsControllerBase
with RepositoryService with AccountService with IssuesService with PullRequestService with MilestonesService with LabelsService with RepositoryService with AccountService with IssuesService with PullRequestService with MilestonesService with LabelsService
@@ -59,7 +62,12 @@ trait PullRequestsControllerBase extends ControllerBase {
case class MergeForm(message: String) case class MergeForm(message: String)
get("/:owner/:repository/pulls")(referrersOnly { repository => get("/:owner/:repository/pulls")(referrersOnly { repository =>
searchPullRequests(None, repository) val q = request.getParameter("q")
if(Option(q).exists(_.contains("is:issue"))){
redirect(s"/${repository.owner}/${repository.name}/issues?q=" + StringUtil.urlEncode(q))
} else {
searchPullRequests(None, repository)
}
}) })
get("/:owner/:repository/pull/:id")(referrersOnly { repository => get("/:owner/:repository/pull/:id")(referrersOnly { repository =>

View File

@@ -415,6 +415,47 @@ object IssuesService {
if(value == null || value.isEmpty || (allow.nonEmpty && !allow.contains(value))) None else Some(value) if(value == null || value.isEmpty || (allow.nonEmpty && !allow.contains(value))) None else Some(value)
} }
/**
* Restores IssueSearchCondition instance from filter query.
*/
def apply(filter: String, milestones: Map[String, Int]): IssueSearchCondition = {
val conditions = filter.split("[  \t]+").map { x =>
val dim = x.split(":")
dim(0) -> dim(1)
}.groupBy(_._1).map { case (key, values) =>
key -> values.map(_._2).toSeq
}
val (sort, direction) = conditions.get("sort").flatMap(_.headOption).getOrElse("created-desc") match {
case "created-asc" => ("created" , "asc" )
case "comments-desc" => ("comments", "desc")
case "comments-asc" => ("comments", "asc" )
case "updated-desc" => ("comments", "desc")
case "updated-asc" => ("comments", "asc" )
case _ => ("created" , "desc")
}
IssueSearchCondition(
conditions.get("label").map(_.toSet).getOrElse(Set.empty),
conditions.get("milestone").flatMap(_.headOption) match {
case None => None
case Some("none") => Some(None)
case Some(x) => Some(milestones.get(x))
},
conditions.get("author").flatMap(_.headOption),
conditions.get("assignee").flatMap(_.headOption),
None, // TODO??
conditions.get("is").getOrElse(Seq.empty).filter(x => x == "open" || x == "closed").headOption.getOrElse("open"),
sort,
direction,
None, // TODO??
Set.empty // TODO??
)
}
/**
* Restores IssueSearchCondition instance from request parameters.
*/
def apply(request: HttpServletRequest): IssueSearchCondition = def apply(request: HttpServletRequest): IssueSearchCondition =
IssueSearchCondition( IssueSearchCondition(
param(request, "labels").map(_.split(",").toSet).getOrElse(Set.empty), param(request, "labels").map(_.split(",").toSet).getOrElse(Set.empty),

View File

@@ -11,22 +11,24 @@
<li class="@if(active == "milestones"){active} last"><a href="@url(repository)/issues/milestones">Milestones</a></li> <li class="@if(active == "milestones"){active} last"><a href="@url(repository)/issues/milestones">Milestones</a></li>
<li class="pull-right"> <li class="pull-right">
@condition.map { condition => @condition.map { condition =>
<div class="input-prepend" style="margin-bottom: 0px;"> <form method="GET" id="search-filter-form">
<div class="btn-group"> <div class="input-prepend" style="margin-bottom: 0px;">
<button class="btn dropdown-toggle" data-toggle="dropdown" style="height: 34px;"> <div class="btn-group">
Filter <button type="button" class="btn dropdown-toggle" data-toggle="dropdown" style="height: 34px;">
<span class="caret"></span> Filter
</button> <span class="caret"></span>
<ul class="dropdown-menu"> </button>
<li><a href="#">Open issues and pull requests</a></li> <ul class="dropdown-menu">
<li><a href="#">Your issues</a></li> <li><a href="#">Open issues and pull requests</a></li>
<li><a href="#">Your pull requests</a></li> <li><a href="#">Your issues</a></li>
<li><a href="#">Everything assigned to you</a></li> <li><a href="#">Your pull requests</a></li>
<li><a href="#">Everything mentioning you</a></li> <li><a href="#">Everything assigned to you</a></li>
</ul> <li><a href="#">Everything mentioning you</a></li>
</ul>
</div>
<input type="text" id="search-filter-box" class="input-xlarge" name="q" style="height: 24px;" value="is:@{if(active == "issues") "issue" else "pr"} @condition.toFilterString"/>
</div> </div>
<input type="text" class="input-xlarge" style="height: 24px;" value="@condition.toFilterString"/> </form>
</div>
} }
@if(loginAccount.isDefined){ @if(loginAccount.isDefined){
<div class="btn-group"> <div class="btn-group">