diff --git a/src/main/scala/app/IssuesController.scala b/src/main/scala/app/IssuesController.scala index 72b3d70..8a98475 100644 --- a/src/main/scala/app/IssuesController.scala +++ b/src/main/scala/app/IssuesController.scala @@ -222,6 +222,53 @@ Ok("updated") }) + post("/:owner/:repository/issues/batchedit/state")(collaboratorsOnly { repository => + val owner = repository.owner + val name = repository.name + val userName = context.loginAccount.get.userName + + params.get("value") collect { + case s if s == "close" => (s.capitalize, Some(s), true) + case s if s == "reopen" => (s.capitalize, Some(s), false) + } map { case (content, action, closed) => + params("checked").split(',') foreach { issueId => + createComment(owner, name, userName, issueId.toInt, content, action) + updateClosed(owner, name, issueId.toInt, closed) + } + redirect("/%s/%s/issues".format(owner, name)) + } getOrElse NotFound + }) + + post("/:owner/:repository/issues/batchedit/label")(collaboratorsOnly { repository => + val owner = repository.owner + val name = repository.name + + params.get("value").map(_.toInt) map { labelId => + params("checked").split(',') foreach { issueId => + getIssueLabel(owner, name, issueId.toInt, labelId) getOrElse { + registerIssueLabel(owner, name, issueId.toInt, labelId) + } + } + redirect("/%s/%s/issues".format(owner, name)) + } getOrElse NotFound + }) + + post("/:owner/:repository/issues/batchedit/assign")(collaboratorsOnly { repository => + params("checked").split(',') foreach { issueId => + updateAssignedUserName(repository.owner, repository.name, issueId.toInt, + params.get("value") filter (_.trim != "")) + } + redirect("/%s/%s/issues".format(repository.owner, repository.name)) + }) + + post("/:owner/:repository/issues/batchedit/milestone")(collaboratorsOnly { repository => + params("checked").split(',') foreach { issueId => + updateMilestoneId(repository.owner, repository.name, issueId.toInt, + params.get("value") collect { case x if x.trim != "" => x.toInt }) + } + redirect("/%s/%s/issues".format(repository.owner, repository.name)) + }) + private def isEditable(owner: String, repository: String, author: String)(implicit context: app.Context): Boolean = hasWritePermission(owner, repository, context.loginAccount) || author == context.loginAccount.get.userName @@ -248,8 +295,9 @@ issues.html.list( searchIssue(owner, repoName, condition, filter, userName, (page - 1) * IssueLimit, IssueLimit), page, - getLabels(owner, repoName), + (getCollaborators(owner, repoName) :+ owner).sorted, getMilestones(owner, repoName).filter(_.closedDate.isEmpty), + getLabels(owner, repoName), countIssue(owner, repoName, condition.copy(state = "open"), filter, userName), countIssue(owner, repoName, condition.copy(state = "closed"), filter, userName), countIssue(owner, repoName, condition, "all", None), diff --git a/src/main/scala/service/IssuesService.scala b/src/main/scala/service/IssuesService.scala index 9641aa4..2c7d55a 100644 --- a/src/main/scala/service/IssuesService.scala +++ b/src/main/scala/service/IssuesService.scala @@ -35,6 +35,9 @@ .map ( _._2 ) .list + def getIssueLabel(owner: String, repository: String, issueId: Int, labelId: Int) = + Query(IssueLabels) filter (_.byPrimaryKey(owner, repository, issueId, labelId)) firstOption + /** * Returns the count of the search result against issues. * diff --git a/src/main/twirl/issues/list.scala.html b/src/main/twirl/issues/list.scala.html index 3fa59f2..b09b114 100644 --- a/src/main/twirl/issues/list.scala.html +++ b/src/main/twirl/issues/list.scala.html @@ -1,7 +1,8 @@ @(issues: List[(model.Issue, List[model.Label], Int)], page: Int, - labels: List[model.Label], + collaborators: List[String], milestones: List[model.Milestone], + labels: List[model.Label], openCount: Int, closedCount: Int, allCount: Int, @@ -181,12 +182,12 @@
- +
@helper.html.dropdown("Label") { @labels.map { label =>
  • - +   @label.labelName @@ -195,14 +196,17 @@ } } @helper.html.dropdown("Assignee") { -
  • Clear assignee
  • +
  • Clear assignee
  • + @collaborators.map { collaborator => +
  • @avatar(collaborator, 20) @collaborator
  • + } } @helper.html.dropdown("Milestone") { -
  • Clear this milestone
  • +
  • Clear this milestone
  • @milestones.map { milestone => -
  • @milestone.title
  • +
  • @milestone.title
  • } } @@ -257,7 +261,28 @@ $('.table-issues input[type=checkbox]').change(function(){ $('.table-issues button').prop('disabled', !$('.table-issues input[type=checkbox]').filter(':checked').length); - }).change(); + }).filter(':first').change(); + + var submitBatchEdit = function(action, value) { + var checked = $('.table-issues input[type=checkbox]').filter(':checked').map(function(){ return this.value; }).get().join(); + $('
    ').attr({action : action, method : 'POST'}) + .append($('').attr('name', 'value').val(value)) + .append($('').attr('name', 'checked').val(checked)) + .submit(); + }; + + $('#state').click(function(){ + submitBatchEdit('@url(repository)/issues/batchedit/state', $(this).text().toLowerCase()); + }); + $('a.toggle-label').click(function(){ + submitBatchEdit('@url(repository)/issues/batchedit/label', $(this).data('id')); + }); + $('a.toggle-assign').click(function(){ + submitBatchEdit('@url(repository)/issues/batchedit/assign', $(this).data('name')); + }); + $('a.toggle-milestone').click(function(){ + submitBatchEdit('@url(repository)/issues/batchedit/milestone', $(this).data('id')); + }); }); }