(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 =>
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) 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 =>
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) 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,9 +11,10 @@
<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 =>
<form method="GET" id="search-filter-form">
<div class="input-prepend" style="margin-bottom: 0px;"> <div class="input-prepend" style="margin-bottom: 0px;">
<div class="btn-group"> <div class="btn-group">
<button class="btn dropdown-toggle" data-toggle="dropdown" style="height: 34px;"> <button type="button" class="btn dropdown-toggle" data-toggle="dropdown" style="height: 34px;">
Filter Filter
<span class="caret"></span> <span class="caret"></span>
</button> </button>
@@ -25,8 +26,9 @@
<li><a href="#">Everything mentioning you</a></li> <li><a href="#">Everything mentioning you</a></li>
</ul> </ul>
</div> </div>
<input type="text" class="input-xlarge" style="height: 24px;" value="@condition.toFilterString"/> <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>
</form>
} }
@if(loginAccount.isDefined){ @if(loginAccount.isDefined){
<div class="btn-group"> <div class="btn-group">