diff --git a/src/main/scala/gitbucket/core/controller/AccountController.scala b/src/main/scala/gitbucket/core/controller/AccountController.scala index c2235f7..045fbfe 100644 --- a/src/main/scala/gitbucket/core/controller/AccountController.scala +++ b/src/main/scala/gitbucket/core/controller/AccountController.scala @@ -20,13 +20,13 @@ class AccountController extends AccountControllerBase with AccountService with RepositoryService with ActivityService with WikiService with LabelsService with SshKeyService with OneselfAuthenticator with UsersAuthenticator with GroupManagerAuthenticator with ReadableUsersAuthenticator - with AccessTokenService with WebHookService with RepositoryCreationService + with AccessTokenService with WebHookService with PrioritiesService with RepositoryCreationService trait AccountControllerBase extends AccountManagementControllerBase { self: AccountService with RepositoryService with ActivityService with WikiService with LabelsService with SshKeyService with OneselfAuthenticator with UsersAuthenticator with GroupManagerAuthenticator with ReadableUsersAuthenticator - with AccessTokenService with WebHookService with RepositoryCreationService => + with AccessTokenService with WebHookService with PrioritiesService with RepositoryCreationService => case class AccountNewForm(userName: String, password: String, fullName: String, mailAddress: String, description: Option[String], url: Option[String], fileId: Option[String]) diff --git a/src/main/scala/gitbucket/core/controller/ApiController.scala b/src/main/scala/gitbucket/core/controller/ApiController.scala index e873ae2..9da265e 100644 --- a/src/main/scala/gitbucket/core/controller/ApiController.scala +++ b/src/main/scala/gitbucket/core/controller/ApiController.scala @@ -33,6 +33,7 @@ with WebHookIssueCommentService with WikiService with ActivityService + with PrioritiesService with OwnerAuthenticator with UsersAuthenticator with GroupManagerAuthenticator @@ -52,6 +53,7 @@ with RepositoryCreationService with IssueCreationService with HandleCommentService + with PrioritiesService with OwnerAuthenticator with UsersAuthenticator with GroupManagerAuthenticator @@ -365,6 +367,7 @@ data.body, data.assignees.headOption, milestone.map(_.milestoneId), + None, data.labels, loginAccount) JsonFormat(ApiIssue(issue, RepositoryName(repository), ApiUser(loginAccount))) diff --git a/src/main/scala/gitbucket/core/controller/IssuesController.scala b/src/main/scala/gitbucket/core/controller/IssuesController.scala index d149915..2474ddd 100644 --- a/src/main/scala/gitbucket/core/controller/IssuesController.scala +++ b/src/main/scala/gitbucket/core/controller/IssuesController.scala @@ -27,6 +27,7 @@ with PullRequestService with WebHookIssueCommentService with CommitsService + with PrioritiesService trait IssuesControllerBase extends ControllerBase { self: IssuesService @@ -41,10 +42,11 @@ with ReferrerAuthenticator with WritableUsersAuthenticator with PullRequestService - with WebHookIssueCommentService => + with WebHookIssueCommentService + with PrioritiesService => case class IssueCreateForm(title: String, content: Option[String], - assignedUserName: Option[String], milestoneId: Option[Int], labelNames: Option[String]) + assignedUserName: Option[String], milestoneId: Option[Int], priorityId: Option[Int], labelNames: Option[String]) case class CommentForm(issueId: Int, content: String) case class IssueStateForm(issueId: Int, content: Option[String]) @@ -53,6 +55,7 @@ "content" -> trim(optional(text())), "assignedUserName" -> trim(optional(text())), "milestoneId" -> trim(optional(number())), + "priorityId" -> trim(optional(number())), "labelNames" -> trim(optional(text())) )(IssueCreateForm.apply) @@ -94,6 +97,7 @@ getIssueLabels(owner, name, issueId.toInt), getAssignableUserNames(owner, name), getMilestonesWithIssueCount(owner, name), + getPriorities(owner, name), getLabels(owner, name), isIssueEditable(repository), isIssueManageable(repository), @@ -109,6 +113,7 @@ html.create( getAssignableUserNames(owner, name), getMilestones(owner, name), + getPriorities(owner, name), getLabels(owner, name), isIssueManageable(repository), getContentTemplate(repository, "ISSUE_TEMPLATE"), @@ -125,6 +130,7 @@ form.content, form.assignedUserName, form.milestoneId, + form.priorityId, form.labelNames.toArray.flatMap(_.split(",")), context.loginAccount.get) @@ -291,6 +297,11 @@ } getOrElse Ok() }) + ajaxPost("/:owner/:repository/issues/:id/priority")(writableUsersOnly { repository => + updatePriorityId(repository.owner, repository.name, params("id").toInt, priorityId("priorityId")) + Ok("updated") + }) + post("/:owner/:repository/issues/batchedit/state")(writableUsersOnly { repository => defining(params.get("value")){ action => action match { @@ -335,6 +346,14 @@ } }) + post("/:owner/:repository/issues/batchedit/priority")(writableUsersOnly { repository => + defining(priorityId("value")){ value => + executeBatch(repository) { + updatePriorityId(repository.owner, repository.name, _, value) + } + } + }) + get("/:owner/:repository/_attached/:file")(referrersOnly { repository => (Directory.getAttachedDir(repository.owner, repository.name) match { case dir if(dir.exists && dir.isDirectory) => @@ -348,6 +367,7 @@ val assignedUserName = (key: String) => params.get(key) filter (_.trim != "") val milestoneId: String => Option[Int] = (key: String) => params.get(key).flatMap(_.toIntOpt) + val priorityId: String => Option[Int] = (key: String) => params.get(key).flatMap(_.toIntOpt) private def executeBatch(repository: RepositoryService.RepositoryInfo)(execute: Int => Unit) = { params("checked").split(',') map(_.toInt) foreach execute @@ -370,6 +390,7 @@ page, getAssignableUserNames(owner, repoName), getMilestones(owner, repoName), + getPriorities(owner, repoName), getLabels(owner, repoName), countIssue(condition.copy(state = "open" ), false, owner -> repoName), countIssue(condition.copy(state = "closed"), false, owner -> repoName), diff --git a/src/main/scala/gitbucket/core/controller/PrioritiesController.scala b/src/main/scala/gitbucket/core/controller/PrioritiesController.scala index b63ee48..4e11f59 100644 --- a/src/main/scala/gitbucket/core/controller/PrioritiesController.scala +++ b/src/main/scala/gitbucket/core/controller/PrioritiesController.scala @@ -27,7 +27,7 @@ get("/:owner/:repository/issues/priorities")(referrersOnly { repository => html.list( getPriorities(repository.owner, repository.name), - Map.empty, // TODO + countIssueGroupByPriorities(repository.owner, repository.name, IssuesService.IssueSearchCondition(), Map.empty), repository, hasDeveloperRole(repository.owner, repository.name, context.loginAccount)) }) @@ -40,7 +40,7 @@ val priorityId = createPriority(repository.owner, repository.name, form.priorityName, form.color.substring(1)) html.priority( getPriority(repository.owner, repository.name, priorityId).get, - Map.empty, // TODO, + countIssueGroupByPriorities(repository.owner, repository.name, IssuesService.IssueSearchCondition(), Map.empty), repository, hasDeveloperRole(repository.owner, repository.name, context.loginAccount)) }) @@ -55,7 +55,7 @@ updatePriority(repository.owner, repository.name, params("priorityId").toInt, form.priorityName, form.color.substring(1)) html.priority( getPriority(repository.owner, repository.name, params("priorityId").toInt).get, - Map.empty, // TODO, + countIssueGroupByPriorities(repository.owner, repository.name, IssuesService.IssueSearchCondition(), Map.empty), repository, hasDeveloperRole(repository.owner, repository.name, context.loginAccount)) }) diff --git a/src/main/scala/gitbucket/core/controller/PullRequestsController.scala b/src/main/scala/gitbucket/core/controller/PullRequestsController.scala index 4029ff0..88328e1 100644 --- a/src/main/scala/gitbucket/core/controller/PullRequestsController.scala +++ b/src/main/scala/gitbucket/core/controller/PullRequestsController.scala @@ -24,14 +24,14 @@ with RepositoryService with AccountService with IssuesService with PullRequestService with MilestonesService with LabelsService with CommitsService with ActivityService with WebHookPullRequestService with ReadableUsersAuthenticator with ReferrerAuthenticator with WritableUsersAuthenticator - with CommitStatusService with MergeService with ProtectedBranchService + with CommitStatusService with MergeService with ProtectedBranchService with PrioritiesService trait PullRequestsControllerBase extends ControllerBase { self: RepositoryService with AccountService with IssuesService with MilestonesService with LabelsService with CommitsService with ActivityService with PullRequestService with WebHookPullRequestService with ReadableUsersAuthenticator with ReferrerAuthenticator with WritableUsersAuthenticator - with CommitStatusService with MergeService with ProtectedBranchService => + with CommitStatusService with MergeService with ProtectedBranchService with PrioritiesService => val pullRequestForm = mapping( "title" -> trim(label("Title" , text(required, maxlength(100)))), @@ -45,6 +45,7 @@ "commitIdTo" -> trim(text(required, maxlength(40))), "assignedUserName" -> trim(optional(text())), "milestoneId" -> trim(optional(number())), + "priorityId" -> trim(optional(number())), "labelNames" -> trim(optional(text())) )(PullRequestForm.apply) @@ -64,6 +65,7 @@ commitIdTo: String, assignedUserName: Option[String], milestoneId: Option[Int], + priorityId: Option[Int], labelNames: Option[String] ) @@ -93,6 +95,7 @@ getIssueLabels(owner, name, issueId), getAssignableUserNames(owner, name), getMilestonesWithIssueCount(owner, name), + getPriorities(owner, name), getLabels(owner, name), commits, diffs, @@ -390,6 +393,7 @@ hasDeveloperRole(originRepository.owner, originRepository.name, context.loginAccount), getAssignableUserNames(originRepository.owner, originRepository.name), getMilestones(originRepository.owner, originRepository.name), + getPriorities(originRepository.owner, originRepository.name), getLabels(originRepository.owner, originRepository.name) ) } @@ -445,6 +449,7 @@ content = form.content, assignedUserName = if (manageable) form.assignedUserName else None, milestoneId = if (manageable) form.milestoneId else None, + priorityId = if (manageable) form.priorityId else None, isPullRequest = true) createPullRequest( @@ -518,6 +523,7 @@ page, getAssignableUserNames(owner, repoName), getMilestones(owner, repoName), + getPriorities(owner, repoName), getLabels(owner, repoName), countIssue(condition.copy(state = "open" ), true, owner -> repoName), countIssue(condition.copy(state = "closed"), true, owner -> repoName), diff --git a/src/main/scala/gitbucket/core/model/Issue.scala b/src/main/scala/gitbucket/core/model/Issue.scala index fd7a5ce..7167195 100644 --- a/src/main/scala/gitbucket/core/model/Issue.scala +++ b/src/main/scala/gitbucket/core/model/Issue.scala @@ -13,12 +13,13 @@ def byPrimaryKey(owner: String, repository: String) = byRepository(owner, repository) } - class IssueOutline(tag: Tag) extends Table[(String, String, Int, Int)](tag, "ISSUE_OUTLINE_VIEW") with IssueTemplate { + class IssueOutline(tag: Tag) extends Table[(String, String, Int, Int, Int)](tag, "ISSUE_OUTLINE_VIEW") with IssueTemplate { val commentCount = column[Int]("COMMENT_COUNT") - def * = (userName, repositoryName, issueId, commentCount) + val priority = column[Int]("PRIORITY") + def * = (userName, repositoryName, issueId, commentCount, priority) } - class Issues(tag: Tag) extends Table[Issue](tag, "ISSUE") with IssueTemplate with MilestoneTemplate { + class Issues(tag: Tag) extends Table[Issue](tag, "ISSUE") with IssueTemplate with MilestoneTemplate with PriorityTemplate { val openedUserName = column[String]("OPENED_USER_NAME") val assignedUserName = column[String]("ASSIGNED_USER_NAME") val title = column[String]("TITLE") @@ -27,7 +28,7 @@ val registeredDate = column[java.util.Date]("REGISTERED_DATE") val updatedDate = column[java.util.Date]("UPDATED_DATE") val pullRequest = column[Boolean]("PULL_REQUEST") - def * = (userName, repositoryName, issueId, openedUserName, milestoneId.?, assignedUserName.?, title, content.?, closed, registeredDate, updatedDate, pullRequest) <> (Issue.tupled, Issue.unapply) + def * = (userName, repositoryName, issueId, openedUserName, milestoneId.?, priorityId.?, assignedUserName.?, title, content.?, closed, registeredDate, updatedDate, pullRequest) <> (Issue.tupled, Issue.unapply) def byPrimaryKey(owner: String, repository: String, issueId: Int) = byIssue(owner, repository, issueId) } @@ -39,6 +40,7 @@ issueId: Int, openedUserName: String, milestoneId: Option[Int], + priorityId: Option[Int], assignedUserName: Option[String], title: String, content: Option[String], diff --git a/src/main/scala/gitbucket/core/service/IssueCreationService.scala b/src/main/scala/gitbucket/core/service/IssueCreationService.scala index 09e7dfb..ad67266 100644 --- a/src/main/scala/gitbucket/core/service/IssueCreationService.scala +++ b/src/main/scala/gitbucket/core/service/IssueCreationService.scala @@ -12,7 +12,7 @@ self: RepositoryService with WebHookIssueCommentService with LabelsService with IssuesService with ActivityService => def createIssue(repository: RepositoryInfo, title:String, body:Option[String], - assignee: Option[String], milestoneId: Option[Int], labelNames: Seq[String], + assignee: Option[String], milestoneId: Option[Int], priorityId: Option[Int], labelNames: Seq[String], loginAccount: Account)(implicit context: Context, s: Session) : Issue = { val owner = repository.owner @@ -23,7 +23,8 @@ // insert issue val issueId = insertIssue(owner, name, userName, title, body, if (manageable) assignee else None, - if (manageable) milestoneId else None) + if (manageable) milestoneId else None, + if (manageable) priorityId else None) val issue: Issue = getIssue(owner, name, issueId.toString).get // insert labels diff --git a/src/main/scala/gitbucket/core/service/IssuesService.scala b/src/main/scala/gitbucket/core/service/IssuesService.scala index 4a9b12c..a782dde 100644 --- a/src/main/scala/gitbucket/core/service/IssuesService.scala +++ b/src/main/scala/gitbucket/core/service/IssuesService.scala @@ -97,6 +97,30 @@ .list.toMap } + /** + * Returns the Map which contains issue count for each priority. + * + * @param owner the repository owner + * @param repository the repository name + * @param condition the search condition + * @return the Map which contains issue count for each priority (key is priority name, value is issue count) + */ + def countIssueGroupByPriorities(owner: String, repository: String, condition: IssueSearchCondition, + filterUser: Map[String, String])(implicit s: Session): Map[String, Int] = { + + searchIssueQuery(Seq(owner -> repository), condition.copy(labels = Set.empty), false) + .join(Priorities).on { case t1 ~ t2 => + t1.byPriority(t2.userName, t2.repositoryName, t2.priorityId) + } + .groupBy { case t1 ~ t2 => + t2.priorityName + } + .map { case priorityName ~ t => + priorityName -> t.length + } + .list.toMap + } + def getCommitStatues(userName: String, repositoryName: String, issueId: Int)(implicit s: Session): Option[CommitStatusInfo] = { val status = PullRequests .filter { pr => @@ -136,21 +160,23 @@ (implicit s: Session): List[IssueInfo] = { // get issues and comment count and labels val result = searchIssueQueryBase(condition, pullRequest, offset, limit, repos) - .joinLeft (IssueLabels) .on { case t1 ~ t2 ~ i ~ t3 => t1.byIssue(t3.userName, t3.repositoryName, t3.issueId) } - .joinLeft (Labels) .on { case t1 ~ t2 ~ i ~ t3 ~ t4 => t3.map(_.byLabel(t4.userName, t4.repositoryName, t4.labelId)) } - .joinLeft (Milestones) .on { case t1 ~ t2 ~ i ~ t3 ~ t4 ~ t5 => t1.byMilestone(t5.userName, t5.repositoryName, t5.milestoneId) } - .sortBy { case t1 ~ t2 ~ i ~ t3 ~ t4 ~ t5 => i asc } - .map { case t1 ~ t2 ~ i ~ t3 ~ t4 ~ t5 => - (t1, t2.commentCount, t4.map(_.labelId), t4.map(_.labelName), t4.map(_.color), t5.map(_.title)) + .joinLeft (IssueLabels) .on { case t1 ~ t2 ~ i ~ t3 => t1.byIssue(t3.userName, t3.repositoryName, t3.issueId) } + .joinLeft (Labels) .on { case t1 ~ t2 ~ i ~ t3 ~ t4 => t3.map(_.byLabel(t4.userName, t4.repositoryName, t4.labelId)) } + .joinLeft (Milestones) .on { case t1 ~ t2 ~ i ~ t3 ~ t4 ~ t5 => t1.byMilestone(t5.userName, t5.repositoryName, t5.milestoneId) } + .joinLeft (Priorities) .on { case t1 ~ t2 ~ i ~ t3 ~ t4 ~ t5 ~ t6 => t1.byPriority(t6.userName, t6.repositoryName, t6.priorityId) } + .sortBy { case t1 ~ t2 ~ i ~ t3 ~ t4 ~ t5 ~ t6 => i asc } + .map { case t1 ~ t2 ~ i ~ t3 ~ t4 ~ t5 ~ t6 => + (t1, t2.commentCount, t4.map(_.labelId), t4.map(_.labelName), t4.map(_.color), t5.map(_.title), t6.map(_.priorityName)) } .list .splitWith { (c1, c2) => c1._1.userName == c2._1.userName && c1._1.repositoryName == c2._1.repositoryName && c1._1.issueId == c2._1.issueId } result.map { issues => issues.head match { - case (issue, commentCount, _, _, _, milestone) => + case (issue, commentCount, _, _, _, milestone, priority) => IssueInfo(issue, issues.flatMap { t => t._3.map (Label(issue.userName, issue.repositoryName, _, t._4.get, t._5.get))} toList, milestone, + priority, commentCount, getCommitStatues(issue.userName, issue.repositoryName, issue.issueId)) }} toList @@ -204,6 +230,10 @@ case "asc" => t1.updatedDate asc case "desc" => t1.updatedDate desc } + case "priority" => condition.direction match { + case "asc" => t2.priority asc + case "desc" => t2.priority desc + } } } .drop(offset).take(limit).zipWithIndex @@ -219,6 +249,7 @@ .foldLeft[Rep[Boolean]](false) ( _ || _ ) && (t1.closed === (condition.state == "closed").bind) && (t1.milestoneId.? isEmpty, condition.milestone == Some(None)) && + (t1.priorityId.? isEmpty, condition.priority == Some(None)) && (t1.assignedUserName.? isEmpty, condition.assigned == Some(None)) && (t1.openedUserName === condition.author.get.bind, condition.author.isDefined) && (t1.pullRequest === pullRequest.bind) && @@ -227,6 +258,11 @@ (t2.byPrimaryKey(t1.userName, t1.repositoryName, t1.milestoneId)) && (t2.title === condition.milestone.get.get.bind) } exists, condition.milestone.flatten.isDefined) && + // Priority filter + (Priorities filter { t2 => + (t2.byPrimaryKey(t1.userName, t1.repositoryName, t1.priorityId)) && + (t2.priorityName === condition.priority.get.get.bind) + } exists, condition.priority.flatten.isDefined) && // Assignee filter (t1.assignedUserName === condition.assigned.get.get.bind, condition.assigned.flatten.isDefined) && // Label filter @@ -253,7 +289,7 @@ } def insertIssue(owner: String, repository: String, loginUser: String, title: String, content: Option[String], - assignedUserName: Option[String], milestoneId: Option[Int], + assignedUserName: Option[String], milestoneId: Option[Int], priorityId: Option[Int], isPullRequest: Boolean = false)(implicit s: Session): Int = { // next id number sql"SELECT ISSUE_ID + 1 FROM ISSUE_ID WHERE USER_NAME = $owner AND REPOSITORY_NAME = $repository FOR UPDATE".as[Int] @@ -264,6 +300,7 @@ id, loginUser, milestoneId, + priorityId, assignedUserName, title, content, @@ -316,6 +353,10 @@ Issues.filter (_.byPrimaryKey(owner, repository, issueId)).map(_.milestoneId?).update (milestoneId) } + def updatePriorityId(owner: String, repository: String, issueId: Int, priorityId: Option[Int])(implicit s: Session): Int = { + Issues.filter (_.byPrimaryKey(owner, repository, issueId)).map(_.priorityId?).update (priorityId) + } + def updateComment(commentId: Int, content: String)(implicit s: Session): Int = { IssueComments.filter (_.byPrimaryKey(commentId)).map(t => (t.content, t.updatedDate)).update(content, currentDate) } @@ -430,6 +471,7 @@ case class IssueSearchCondition( labels: Set[String] = Set.empty, milestone: Option[Option[String]] = None, + priority: Option[Option[String]] = None, author: Option[String] = None, assigned: Option[Option[String]] = None, mentioned: Option[String] = None, @@ -459,6 +501,10 @@ case Some(x) => s"milestone:${x}" case None => "no:milestone" }}, + priority.map { _ match { + case Some(x) => s"priority:${x}" + case None => "no:priority" + }}, (sort, direction) match { case ("created" , "desc") => None case ("created" , "asc" ) => Some("sort:created-asc") @@ -466,6 +512,8 @@ case ("comments", "asc" ) => Some("sort:comments-asc") case ("updated" , "desc") => Some("sort:updated-desc") case ("updated" , "asc" ) => Some("sort:updated-asc") + case ("priority", "desc") => Some("sort:priority-desc") + case ("priority", "asc" ) => Some("sort:priority-asc") case x => throw new MatchError(x) }, visibility.map(visibility => s"visibility:${visibility}") @@ -480,6 +528,10 @@ case Some(x) => "milestone=" + urlEncode(x) case None => "milestone=none" }, + priority.map { + case Some(x) => "priority=" + urlEncode(x) + case None => "priority=none" + }, author .map(x => "author=" + urlEncode(x)), assigned.map { case Some(x) => "assigned=" + urlEncode(x) @@ -512,6 +564,10 @@ case "none" => None case x => Some(x) }, + param(request, "priority").map { + case "none" => None + case x => Some(x) + }, param(request, "author"), param(request, "assigned").map { case "none" => None @@ -519,7 +575,7 @@ }, param(request, "mentioned"), param(request, "state", Seq("open", "closed")).getOrElse("open"), - param(request, "sort", Seq("created", "comments", "updated")).getOrElse("created"), + param(request, "sort", Seq("created", "comments", "updated", "priority")).getOrElse("created"), param(request, "direction", Seq("asc", "desc")).getOrElse("desc"), param(request, "visibility"), param(request, "groups").map(_.split(",").toSet).getOrElse(Set.empty) @@ -535,6 +591,6 @@ case class CommitStatusInfo(count: Int, successCount: Int, context: Option[String], state: Option[CommitState], targetUrl: Option[String], description: Option[String]) - case class IssueInfo(issue: Issue, labels: List[Label], milestone: Option[String], commentCount: Int, status:Option[CommitStatusInfo]) + case class IssueInfo(issue: Issue, labels: List[Label], milestone: Option[String], priority: Option[String], commentCount: Int, status:Option[CommitStatusInfo]) } diff --git a/src/main/scala/gitbucket/core/service/PrioritiesService.scala b/src/main/scala/gitbucket/core/service/PrioritiesService.scala index de57027..7752adf 100644 --- a/src/main/scala/gitbucket/core/service/PrioritiesService.scala +++ b/src/main/scala/gitbucket/core/service/PrioritiesService.scala @@ -50,7 +50,11 @@ } def deletePriority(owner: String, repository: String, priorityId: Int)(implicit s: Session): Unit = { - // TODO update affected issues + Issues.filter(_.byRepository(owner, repository)) + .filter(_.priorityId === priorityId) + .map(_.priorityId?) + .update(None) + Priorities.filter(_.byPrimaryKey(owner, repository, priorityId)).delete } } diff --git a/src/main/scala/gitbucket/core/service/RepositoryCreationService.scala b/src/main/scala/gitbucket/core/service/RepositoryCreationService.scala index 7381bbc..ef426f8 100644 --- a/src/main/scala/gitbucket/core/service/RepositoryCreationService.scala +++ b/src/main/scala/gitbucket/core/service/RepositoryCreationService.scala @@ -10,7 +10,7 @@ import org.eclipse.jgit.lib.{FileMode, Constants} trait RepositoryCreationService { - self: AccountService with RepositoryService with LabelsService with WikiService with ActivityService => + self: AccountService with RepositoryService with LabelsService with WikiService with ActivityService with PrioritiesService => def createRepository(loginAccount: Account, owner: String, name: String, description: Option[String], isPrivate: Boolean, createReadme: Boolean) (implicit s: Session) { @@ -30,6 +30,9 @@ // Insert default labels insertDefaultLabels(owner, name) + // Insert default priorities + insertDefaultPriorities(owner, name) + // Create the actual repository val gitdir = getRepositoryDir(owner, name) JGitUtil.initRepository(gitdir) @@ -74,5 +77,9 @@ createLabel(userName, repositoryName, "wontfix", "ffffff") } - + def insertDefaultPriorities(userName: String, repositoryName: String)(implicit s: Session): Unit = { + createPriority(userName, repositoryName, "high", "fc2929") + createPriority(userName, repositoryName, "medium", "fcc629") + createPriority(userName, repositoryName, "low", "acacac") + } } diff --git a/src/main/twirl/gitbucket/core/dashboard/issueslist.scala.html b/src/main/twirl/gitbucket/core/dashboard/issueslist.scala.html index 7463451..ec28060 100644 --- a/src/main/twirl/gitbucket/core/dashboard/issueslist.scala.html +++ b/src/main/twirl/gitbucket/core/dashboard/issueslist.scala.html @@ -17,7 +17,7 @@ - @issues.map { case IssueInfo(issue, labels, milestone, commentCount, commitStatus) => + @issues.map { case IssueInfo(issue, labels, milestone, priority, commentCount, commitStatus) => @issue.userName/@issue.repositoryName ・ diff --git a/src/main/twirl/gitbucket/core/issues/create.scala.html b/src/main/twirl/gitbucket/core/issues/create.scala.html index bd73e61..f1a8134 100644 --- a/src/main/twirl/gitbucket/core/issues/create.scala.html +++ b/src/main/twirl/gitbucket/core/issues/create.scala.html @@ -1,5 +1,6 @@ @(collaborators: List[String], milestones: List[gitbucket.core.model.Milestone], + priorities: List[gitbucket.core.model.Priority], labels: List[gitbucket.core.model.Label], isManageable: Boolean, content: String, @@ -29,7 +30,7 @@
- @gitbucket.core.issues.html.issueinfo(None, Nil, Nil, collaborators, milestones.map(x => (x, 0, 0)), labels, isManageable, repository) + @gitbucket.core.issues.html.issueinfo(None, Nil, Nil, collaborators, milestones.map(x => (x, 0, 0)), priorities, labels, isManageable, repository)
diff --git a/src/main/twirl/gitbucket/core/issues/issue.scala.html b/src/main/twirl/gitbucket/core/issues/issue.scala.html index e42ffbf..6ffce80 100644 --- a/src/main/twirl/gitbucket/core/issues/issue.scala.html +++ b/src/main/twirl/gitbucket/core/issues/issue.scala.html @@ -3,6 +3,7 @@ issueLabels: List[gitbucket.core.model.Label], collaborators: List[String], milestones: List[(gitbucket.core.model.Milestone, Int, Int)], + priorities: List[gitbucket.core.model.Priority], labels: List[gitbucket.core.model.Label], isEditable: Boolean, isManageable: Boolean, @@ -54,7 +55,7 @@ @gitbucket.core.issues.html.commentform(issue, true, isEditable, isManageable, repository)
- @gitbucket.core.issues.html.issueinfo(Some(issue), comments, issueLabels, collaborators, milestones, labels, isManageable, repository) + @gitbucket.core.issues.html.issueinfo(Some(issue), comments, issueLabels, collaborators, milestones, priorities, labels, isManageable, repository)
} diff --git a/src/main/twirl/gitbucket/core/issues/issueinfo.scala.html b/src/main/twirl/gitbucket/core/issues/issueinfo.scala.html index 27cd255..5bc9507 100644 --- a/src/main/twirl/gitbucket/core/issues/issueinfo.scala.html +++ b/src/main/twirl/gitbucket/core/issues/issueinfo.scala.html @@ -3,6 +3,7 @@ issueLabels: List[gitbucket.core.model.Label], collaborators: List[String], milestones: List[(gitbucket.core.model.Milestone, Int, Int)], + priorities: List[gitbucket.core.model.Priority], labels: List[gitbucket.core.model.Label], isManageable: Boolean, repository: gitbucket.core.service.RepositoryService.RepositoryInfo)(implicit context: gitbucket.core.controller.Context) @@ -32,6 +33,40 @@ @gitbucket.core.issues.html.labellist(issueLabels)
+ +
+ Priority + @if(isManageable){ +
+ @gitbucket.core.helper.html.dropdown("Edit", right = true, filter = ("priority", "Filter Priority")) { +
  • Clear priority
  • + @priorities.map { priority => +
  • + + @gitbucket.core.helper.html.checkicon(issue.flatMap(is => is.priorityId).map(id => id == priority.priorityId).getOrElse(false)) +   + @priority.priorityName + +
  • + } + } +
    + } +
    + + @issue.flatMap(_.priorityId).map { priorityId => + @priorities.collect { case priority if(priority.priorityId == priorityId) => + @priority.priorityName + } + }.getOrElse { + No priority + } + +@if(issue.isEmpty){ + +} +
    +
    Milestone @if(isManageable){ @@ -152,6 +187,19 @@ ); }); + $('a.priority').click(function(){ + var priorityName = $(this).data('name'); + var priorityId = $(this).data('id'); + var color = $(this).data('color'); + var fontColor = $(this).data('font-color'); + $.post('@helpers.url(repository)/issues/@issue.issueId/priority', + { priorityId: priorityId }, + function(data){ + displayPriority(priorityName, priorityId, color, fontColor); + } + ); + }); + $('a.assign').click(function(){ var $this = $(this); var userName = $this.data('name'); @@ -188,6 +236,15 @@ $('input[name=milestoneId]').val(milestoneId); }); + $('a.priority').click(function(){ + var priorityName = $(this).data('name'); + var priorityId = $(this).data('id'); + var color = $(this).data('color'); + var fontColor = $(this).data('font-color'); + displayPriority(priorityName, priorityId, color, fontColor); + $('input[name=priorityId]').val(priorityId); + }); + $('a.assign').click(function(){ var $this = $(this); var userName = $this.data('name'); @@ -222,6 +279,22 @@ } } + function displayPriority(priorityName, priorityId, color, fontColor){ + $('a.priority i.octicon-check').removeClass('octicon-check'); + if(priorityId == ''){ + $('#label-priority').html($('').text('No priority')); + } else { + $('#label-priority').html($('').text(priorityName) + .attr('href', '@helpers.url(repository)/issues?priority=' + encodeURIComponent(priorityName) + '&state=open') + .css({ + "background-color": color, + "color": fontColor + })); + + $('a.priority[data-id=' + priorityId + '] i').addClass('octicon-check'); + } + } + function displayAssignee($this, userName){ $('a.assign i.octicon-check').removeClass('octicon-check'); if(userName == ''){ diff --git a/src/main/twirl/gitbucket/core/issues/list.scala.html b/src/main/twirl/gitbucket/core/issues/list.scala.html index e90eb65..21d25c4 100644 --- a/src/main/twirl/gitbucket/core/issues/list.scala.html +++ b/src/main/twirl/gitbucket/core/issues/list.scala.html @@ -3,6 +3,7 @@ page: Int, collaborators: List[String], milestones: List[gitbucket.core.model.Milestone], + priorities: List[gitbucket.core.model.Priority], labels: List[gitbucket.core.model.Label], openCount: Int, closedCount: Int, @@ -38,7 +39,7 @@ } } - @gitbucket.core.issues.html.listparts(target, issues, page, openCount, closedCount, condition, collaborators, milestones, labels, Some(repository), isManageable) + @gitbucket.core.issues.html.listparts(target, issues, page, openCount, closedCount, condition, collaborators, milestones, priorities, labels, Some(repository), isManageable) @if(isManageable){
    @@ -119,6 +120,9 @@ $('a.toggle-milestone').click(function(){ submitBatchEdit('@helpers.url(repository)/issues/batchedit/milestone', $(this).data('id')); }); + $('a.toggle-priority').click(function(){ + submitBatchEdit('@helpers.url(repository)/issues/batchedit/priority', $(this).data('id')); + }); }); } diff --git a/src/main/twirl/gitbucket/core/issues/listparts.scala.html b/src/main/twirl/gitbucket/core/issues/listparts.scala.html index 034aa84..df2affa 100644 --- a/src/main/twirl/gitbucket/core/issues/listparts.scala.html +++ b/src/main/twirl/gitbucket/core/issues/listparts.scala.html @@ -6,6 +6,7 @@ condition: gitbucket.core.service.IssuesService.IssueSearchCondition, collaborators: List[String] = Nil, milestones: List[gitbucket.core.model.Milestone] = Nil, + priorities: List[gitbucket.core.model.Priority] = Nil, labels: List[gitbucket.core.model.Label] = Nil, repository: Option[gitbucket.core.service.RepositoryService.RepositoryInfo] = None, isManageable: Boolean = false)(implicit context: gitbucket.core.controller.Context) @@ -48,6 +49,22 @@ } } + @gitbucket.core.helper.html.dropdown("Priority", filter = ("priority", "Find Priority...")) { +
  • + + @gitbucket.core.helper.html.checkicon(condition.priority == Some(None)) Issues with no priority + +
  • + @priorities.map { priority => +
  • + + @gitbucket.core.helper.html.checkicon(condition.priority == Some(Some(priority.priorityName))) +    + @priority.priorityName + +
  • + } + } @gitbucket.core.helper.html.dropdown("Milestone", filter = ("milestone", "Find Milestone...")) {
  • @@ -89,6 +106,16 @@
  • + + @gitbucket.core.helper.html.checkicon(condition.sort == "priority" && condition.direction == "asc") Highest priority + +
  • +
  • + + @gitbucket.core.helper.html.checkicon(condition.sort == "priority" && condition.direction == "desc") Lowest priority + +
  • +
  • @gitbucket.core.helper.html.checkicon(condition.sort == "comments" && condition.direction == "desc") Most commented @@ -127,6 +154,14 @@
  • } } + @gitbucket.core.helper.html.dropdown("Priority", filter = ("priority", "Find Priority...")) { +
  • No priority
  • + @priorities.map { priority => +
  • +   + @priority.priorityName
  • + } + } @gitbucket.core.helper.html.dropdown("Milestone", filter = ("milestone", "Find Milestone...")) {
  • No milestone
  • @milestones.filter(_.closedDate.isEmpty).map { milestone => @@ -171,7 +206,7 @@ } - @issues.map { case IssueInfo(issue, labels, milestone, commentCount, commitStatus) => + @issues.map { case IssueInfo(issue, labels, milestone, priority, commentCount, commitStatus) => @if(isManageable){ @@ -208,6 +243,10 @@
    #@issue.issueId opened @gitbucket.core.helper.html.datetimeago(issue.registeredDate) by @helpers.user(issue.openedUserName, styleClass="username") + @priority.map(priority => priorities.filter(p => p.priorityName == priority).head).map { priority => + + @priority.priorityName + } @milestone.map { milestone => @milestone } diff --git a/src/main/twirl/gitbucket/core/pulls/compare.scala.html b/src/main/twirl/gitbucket/core/pulls/compare.scala.html index 714f324..5a47eb2 100644 --- a/src/main/twirl/gitbucket/core/pulls/compare.scala.html +++ b/src/main/twirl/gitbucket/core/pulls/compare.scala.html @@ -14,6 +14,7 @@ hasOriginWritePermission: Boolean, collaborators: List[String], milestones: List[gitbucket.core.model.Milestone], + priorities: List[gitbucket.core.model.Priority], labels: List[gitbucket.core.model.Label])(implicit context: gitbucket.core.controller.Context) @import gitbucket.core.view.helpers @gitbucket.core.html.main(s"Pull requests - ${repository.owner}/${repository.name}", Some(repository)){ @@ -81,7 +82,7 @@
    - @gitbucket.core.issues.html.issueinfo(None, Nil, Nil, collaborators, milestones.map((_, 0, 0)), labels, hasOriginWritePermission, repository) + @gitbucket.core.issues.html.issueinfo(None, Nil, Nil, collaborators, milestones.map((_, 0, 0)), priorities, labels, hasOriginWritePermission, repository)
    diff --git a/src/main/twirl/gitbucket/core/pulls/conversation.scala.html b/src/main/twirl/gitbucket/core/pulls/conversation.scala.html index c05d293..6836c06 100644 --- a/src/main/twirl/gitbucket/core/pulls/conversation.scala.html +++ b/src/main/twirl/gitbucket/core/pulls/conversation.scala.html @@ -5,6 +5,7 @@ issueLabels: List[gitbucket.core.model.Label], collaborators: List[String], milestones: List[(gitbucket.core.model.Milestone, Int, Int)], + priorities: List[gitbucket.core.model.Priority], labels: List[gitbucket.core.model.Label], isEditable: Boolean, isManageable: Boolean, @@ -45,7 +46,7 @@ }
    - @gitbucket.core.issues.html.issueinfo(Some(issue), comments, issueLabels, collaborators, milestones, labels, isManageable, repository) + @gitbucket.core.issues.html.issueinfo(Some(issue), comments, issueLabels, collaborators, milestones, priorities, labels, isManageable, repository)