Separate pull request tab contents as individual actions

This commit is contained in:
Naoki Takezoe
2018-04-19 18:39:25 +09:00
parent 6150625e99
commit a39a0292b6
10 changed files with 331 additions and 132 deletions

View File

@@ -113,52 +113,91 @@ trait PullRequestsControllerBase extends ControllerBase {
val name = repository.name
getPullRequest(owner, name, issueId) map {
case (issue, pullreq) =>
using(Git.open(getRepositoryDir(owner, name))) {
git =>
val (commits, diffs) =
getRequestCompareInfo(owner, name, pullreq.commitIdFrom, owner, name, pullreq.commitIdTo)
val (commits, _) =
getRequestCompareInfo(owner, name, pullreq.commitIdFrom, owner, name, pullreq.commitIdTo)
val comments = (commits.flatten
.map(commit => getCommitComments(owner, name, commit.id, true))
.flatten
.toList ::: getComments(owner, name, issueId))
.groupBy {
case x: IssueComment => (Some(x.commentId), None, None, None)
case x: CommitComment => (None, x.fileName, x.oldLine, x.newLine)
}
.toList
.map {
case ((Some(_), _, _, _), comments) =>
comments.head
case ((None, Some(fileName), _, _), comments) =>
CommitComments(
fileName = fileName,
commentedUserName = comments.head.commentedUserName,
registeredDate = comments.head.registeredDate,
comments = comments.map(_.asInstanceOf[CommitComment])
)
}
.sortWith(_.registeredDate before _.registeredDate)
html.conversation(
issue,
pullreq,
commits.flatten,
getPullRequestComments(owner, name, issue.issueId, commits.flatten),
getIssueLabels(owner, name, issueId),
getAssignableUserNames(owner, name),
getMilestonesWithIssueCount(owner, name),
getPriorities(owner, name),
getLabels(owner, name),
//commits,
//diffs,
isEditable(repository),
isManageable(repository),
hasDeveloperRole(pullreq.requestUserName, pullreq.requestRepositoryName, context.loginAccount),
repository,
getRepository(pullreq.requestUserName, pullreq.requestRepositoryName)
//flash.toMap.map(f => f._1 -> f._2.toString)
)
html.pullreq(
issue,
pullreq,
comments,
getIssueLabels(owner, name, issueId),
getAssignableUserNames(owner, name),
getMilestonesWithIssueCount(owner, name),
getPriorities(owner, name),
getLabels(owner, name),
commits,
diffs,
isEditable(repository),
isManageable(repository),
hasDeveloperRole(pullreq.requestUserName, pullreq.requestRepositoryName, context.loginAccount),
repository,
getRepository(pullreq.requestUserName, pullreq.requestRepositoryName),
flash.toMap.map(f => f._1 -> f._2.toString)
)
}
// html.pullreq(
// issue,
// pullreq,
// comments,
// getIssueLabels(owner, name, issueId),
// getAssignableUserNames(owner, name),
// getMilestonesWithIssueCount(owner, name),
// getPriorities(owner, name),
// getLabels(owner, name),
// commits,
// diffs,
// isEditable(repository),
// isManageable(repository),
// hasDeveloperRole(pullreq.requestUserName, pullreq.requestRepositoryName, context.loginAccount),
// repository,
// getRepository(pullreq.requestUserName, pullreq.requestRepositoryName),
// flash.toMap.map(f => f._1 -> f._2.toString)
// )
}
} getOrElse NotFound()
})
get("/:owner/:repository/pull/:id/commits")(referrersOnly { repository =>
params("id").toIntOpt.flatMap { issueId =>
val owner = repository.owner
val name = repository.name
getPullRequest(owner, name, issueId) map {
case (issue, pullreq) =>
val (commits, _) =
getRequestCompareInfo(owner, name, pullreq.commitIdFrom, owner, name, pullreq.commitIdTo)
html.commits(
issue,
pullreq,
commits,
getPullRequestComments(owner, name, issue.issueId, commits.flatten),
isManageable(repository),
repository
)
}
} getOrElse NotFound()
})
get("/:owner/:repository/pull/:id/files")(referrersOnly { repository =>
params("id").toIntOpt.flatMap {
issueId =>
val owner = repository.owner
val name = repository.name
getPullRequest(owner, name, issueId) map {
case (issue, pullreq) =>
val (commits, diffs) =
getRequestCompareInfo(owner, name, pullreq.commitIdFrom, owner, name, pullreq.commitIdTo)
html.files(
issue,
pullreq,
diffs,
commits.flatten,
getPullRequestComments(owner, name, issue.issueId, commits.flatten),
isManageable(repository),
repository
)
}
} getOrElse NotFound()
})

View File

@@ -1,7 +1,7 @@
package gitbucket.core.model
import java.util.Date
trait Comment {
sealed trait Comment {
val commentedUserName: String
val registeredDate: java.util.Date
}

View File

@@ -1,6 +1,6 @@
package gitbucket.core.service
import gitbucket.core.model.{Issue, PullRequest, CommitStatus, CommitState, CommitComment}
import gitbucket.core.model.{CommitComments => _, Session => _, _}
import gitbucket.core.model.Profile._
import gitbucket.core.model.Profile.profile.blockingApi._
import difflib.{Delta, DiffUtils}
@@ -12,6 +12,7 @@ import gitbucket.core.util.JGitUtil.{CommitInfo, DiffInfo}
import gitbucket.core.view
import gitbucket.core.view.helpers
import org.eclipse.jgit.api.Git
import scala.collection.JavaConverters._
trait PullRequestService { self: IssuesService with CommitsService =>
@@ -314,11 +315,38 @@ trait PullRequestService { self: IssuesService with CommitsService =>
helpers.date(commit1.commitTime) == view.helpers.date(commit2.commitTime)
}
// TODO Isolate to an another method?
val diffs = JGitUtil.getDiffs(newGit, Some(oldId.getName), newId.getName, true, false)
(commits, diffs)
}
def getPullRequestComments(userName: String, repositoryName: String, issueId: Int, commits: Seq[CommitInfo])(
implicit s: Session
): Seq[Comment] = {
(commits
.map(commit => getCommitComments(userName, repositoryName, commit.id, true))
.flatten ++ getComments(userName, repositoryName, issueId))
.groupBy {
case x: IssueComment => (Some(x.commentId), None, None, None)
case x: CommitComment => (None, x.fileName, x.oldLine, x.newLine)
case x => throw new MatchError(x)
}
.toSeq
.map {
case ((Some(_), _, _, _), comments) =>
comments.head
case ((None, Some(fileName), _, _), comments) =>
gitbucket.core.model.CommitComments(
fileName = fileName,
commentedUserName = comments.head.commentedUserName,
registeredDate = comments.head.registeredDate,
comments = comments.map(_.asInstanceOf[CommitComment])
)
}
.sortWith(_.registeredDate before _.registeredDate)
}
}
object PullRequestService {

View File

@@ -4,7 +4,6 @@
repository: gitbucket.core.service.RepositoryService.RepositoryInfo,
pullreq: Option[gitbucket.core.model.PullRequest] = None)(implicit context: gitbucket.core.controller.Context)
@import gitbucket.core.view.helpers
@import gitbucket.core.model.CommitComments
@issueOrPullRequest()={ @if(issue.exists(_.isPullRequest))( "pull request" )else( "issue" ) }
@showFormattedComment(comment: gitbucket.core.model.IssueComment)={
<div class="panel panel-default issue-comment-box" id="comment-@comment.commentId">
@@ -233,9 +232,14 @@
}
}
}
case comments: CommitComments => {
case comments: gitbucket.core.model.CommitComments => {
@gitbucket.core.helper.html.commitcomments(comments, isManageable, repository, pullreq.map(_.commitIdTo))
}
case comment: gitbucket.core.model.CommitComment => {
@gitbucket.core.helper.html.commitcomments(gitbucket.core.model.CommitComments(
comment.fileName.getOrElse(""), comment.commentedUserName, comment.registeredDate, Seq(comment)
), isManageable, repository, pullreq.map(_.commitIdTo))
}
}
<script>
$(function(){

View File

@@ -1,41 +1,47 @@
@(commits: Seq[Seq[gitbucket.core.util.JGitUtil.CommitInfo]],
@(issue: gitbucket.core.model.Issue,
pullreq: gitbucket.core.model.PullRequest,
commits: Seq[Seq[gitbucket.core.util.JGitUtil.CommitInfo]],
comments: Seq[gitbucket.core.model.Comment],
isManageable: Boolean,
repository: gitbucket.core.service.RepositoryService.RepositoryInfo)(implicit context: gitbucket.core.controller.Context)
@import gitbucket.core.view.helpers
<table class="table table-bordered">
@commits.map { day =>
<tr>
<th rowspan="@day.size" width="100">@helpers.date(day.head.commitTime)</th>
@day.zipWithIndex.map { case (commit, i) =>
@if(i != 0){ <tr> }
<td>
<div class="pull-right text-right">
<a href="@helpers.url(repository)/commit/@commit.id" class="monospace commit-message strong"><i class="octicon octicon-diff" style="color: black;"></i>@commit.id.substring(0, 7)</a><br>
<a href="@helpers.url(repository)/tree/@commit.id" class="button-link">Browse files »</a>
</div>
<div>
<div class="commit-avatar-image">@helpers.avatarLink(commit, 40)</div>
@gitbucket.core.pulls.html.menu("commits", issue, pullreq, commits.flatten, comments, isManageable, repository){
<table class="table table-bordered">
@commits.map { day =>
<tr>
<th rowspan="@day.size" width="100">@helpers.date(day.head.commitTime)</th>
@day.zipWithIndex.map { case (commit, i) =>
@if(i != 0){ <tr> }
<td>
<div class="pull-right text-right">
<a href="@helpers.url(repository)/commit/@commit.id" class="monospace commit-message strong"><i class="octicon octicon-diff" style="color: black;"></i>@commit.id.substring(0, 7)</a><br>
<a href="@helpers.url(repository)/tree/@commit.id" class="button-link">Browse files »</a>
</div>
<div>
<a href="@helpers.url(repository)/commit/@commit.id" class="commit-message strong">@helpers.link(commit.summary, repository)</a>
@if(commit.description.isDefined){
<a href="javascript:void(0)" onclick="$('#description-@commit.id').toggle();" class="omit">...</a>
}
<br>
@if(commit.description.isDefined){
<pre id="description-@commit.id" style="display: none;" class="commit-description">@helpers.link(commit.description.get, repository)</pre>
}
<div class="commit-avatar-image">@helpers.avatarLink(commit, 40)</div>
<div>
@if(commit.isDifferentFromAuthor) {
@helpers.user(commit.authorName, commit.authorEmailAddress, "username")
<span class="muted">authored @gitbucket.core.helper.html.datetimeago(commit.authorTime)</span>
<span class="octicon octicon-arrow-right" style="margin-top : -2px;"></span>
<a href="@helpers.url(repository)/commit/@commit.id" class="commit-message strong">@helpers.link(commit.summary, repository)</a>
@if(commit.description.isDefined){
<a href="javascript:void(0)" onclick="$('#description-@commit.id').toggle();" class="omit">...</a>
}
@helpers.user(commit.committerName, commit.committerEmailAddress, "username")
<span class="muted">committed @gitbucket.core.helper.html.datetimeago(commit.commitTime)</span>
<br>
@if(commit.description.isDefined){
<pre id="description-@commit.id" style="display: none;" class="commit-description">@helpers.link(commit.description.get, repository)</pre>
}
<div>
@if(commit.isDifferentFromAuthor) {
@helpers.user(commit.authorName, commit.authorEmailAddress, "username")
<span class="muted">authored @gitbucket.core.helper.html.datetimeago(commit.authorTime)</span>
<span class="octicon octicon-arrow-right" style="margin-top : -2px;"></span>
}
@helpers.user(commit.committerName, commit.committerEmailAddress, "username")
<span class="muted">committed @gitbucket.core.helper.html.datetimeago(commit.commitTime)</span>
</div>
</div>
</div>
</div>
</td>
</tr>
}
</td>
</tr>
}
}
</table>
}
</table>

View File

@@ -1,7 +1,7 @@
@(issue: gitbucket.core.model.Issue,
pullreq: gitbucket.core.model.PullRequest,
commits: Seq[gitbucket.core.util.JGitUtil.CommitInfo],
comments: List[gitbucket.core.model.Comment],
comments: Seq[gitbucket.core.model.Comment],
issueLabels: List[gitbucket.core.model.Label],
collaborators: List[String],
milestones: List[(gitbucket.core.model.Milestone, Int, Int)],
@@ -13,52 +13,54 @@
repository: gitbucket.core.service.RepositoryService.RepositoryInfo,
forkedRepository: Option[gitbucket.core.service.RepositoryService.RepositoryInfo])(implicit context: gitbucket.core.controller.Context)
@import gitbucket.core.view.helpers
<div class="col-md-9">
<div id="comment-list">
@gitbucket.core.issues.html.commentlist(Some(issue), comments, isManageable, repository, Some(pullreq))
@gitbucket.core.pulls.html.menu("conversation", issue, pullreq, commits, comments, isManageable, repository){
<div class="col-md-9">
<div id="comment-list">
@gitbucket.core.issues.html.commentlist(Some(issue), comments.toList, isManageable, repository, Some(pullreq))
</div>
@defining(comments.flatMap {
case comment: gitbucket.core.model.IssueComment => Some(comment)
case other => None
}.exists(_.action == "merge")){ merged =>
@if(!issue.closed){
<div class="check-conflict" style="display: none;">
<div class="issue-comment-box" style="background-color: #fbeed5">
<div class="box-content" style="border: 1px solid #c09853; padding: 10px;">
<img src="@helpers.assets("/common/images/indicator.gif")"/> Checking...
</div>
</div>
</div>
}
@if(isManageableForkedRepository && issue.closed && merged &&
forkedRepository.map(r => (r.branchList.contains(pullreq.requestBranch) && r.repository.defaultBranch != pullreq.requestBranch)).getOrElse(false)){
<div class="issue-comment-box" style="background-color: #d0eeff;">
<div class="box-content" style="border: 1px solid #87a8c9; padding: 10px;">
<a href="@helpers.url(repository)/pull/@issue.issueId/delete_branch" class="btn btn-info pull-right delete-branch" data-name="@pullreq.requestBranch">Delete branch</a>
<div>
<span class="strong">Pull request successfully merged and closed</span>
</div>
<span class="small muted">You're all set. The <span class="label label-info monospace">@pullreq.requestBranch</span> branch can now be safely deleted.</span>
</div>
</div>
}
@gitbucket.core.issues.html.commentform(issue, !merged, isEditable, isManageable, repository)
}
</div>
@defining(comments.flatMap {
case comment: gitbucket.core.model.IssueComment => Some(comment)
case other => None
}.exists(_.action == "merge")){ merged =>
@if(!issue.closed){
<div class="check-conflict" style="display: none;">
<div class="issue-comment-box" style="background-color: #fbeed5">
<div class="box-content" style="border: 1px solid #c09853; padding: 10px;">
<img src="@helpers.assets("/common/images/indicator.gif")"/> Checking...
</div>
</div>
</div>
<div class="col-md-3">
@gitbucket.core.issues.html.issueinfo(Some(issue), comments.toList, issueLabels, collaborators, milestones, priorities, None, labels, isManageable, repository)
</div>
<script>
$(function(){
@if(commits.nonEmpty){
var checkConflict = $('.check-conflict').show();
if(checkConflict.length){
$.get('@helpers.url(repository)/pull/@issue.issueId/mergeguide', function(data){ $('.check-conflict').html(data); });
}
}
@if(isManageableForkedRepository && issue.closed && merged &&
forkedRepository.map(r => (r.branchList.contains(pullreq.requestBranch) && r.repository.defaultBranch != pullreq.requestBranch)).getOrElse(false)){
<div class="issue-comment-box" style="background-color: #d0eeff;">
<div class="box-content" style="border: 1px solid #87a8c9; padding: 10px;">
<a href="@helpers.url(repository)/pull/@issue.issueId/delete_branch" class="btn btn-info pull-right delete-branch" data-name="@pullreq.requestBranch">Delete branch</a>
<div>
<span class="strong">Pull request successfully merged and closed</span>
</div>
<span class="small muted">You're all set. The <span class="label label-info monospace">@pullreq.requestBranch</span> branch can now be safely deleted.</span>
</div>
</div>
}
@gitbucket.core.issues.html.commentform(issue, !merged, isEditable, isManageable, repository)
}
</div>
<div class="col-md-3">
@gitbucket.core.issues.html.issueinfo(Some(issue), comments, issueLabels, collaborators, milestones, priorities, None, labels, isManageable, repository)
</div>
<script>
$(function(){
@if(commits.nonEmpty){
var checkConflict = $('.check-conflict').show();
if(checkConflict.length){
$.get('@helpers.url(repository)/pull/@issue.issueId/mergeguide', function(data){ $('.check-conflict').html(data); });
}
}
$('.delete-branch').click(function(e){
var branchName = $(e.target).data('name');
return confirm('Are you sure you want to remove the ' + branchName + ' branch?');
$('.delete-branch').click(function(e){
var branchName = $(e.target).data('name');
return confirm('Are you sure you want to remove the ' + branchName + ' branch?');
});
});
});
</script>
</script>
}

View File

@@ -0,0 +1,19 @@
@(issue: gitbucket.core.model.Issue,
pullreq: gitbucket.core.model.PullRequest,
diffs: Seq[gitbucket.core.util.JGitUtil.DiffInfo],
commits: Seq[gitbucket.core.util.JGitUtil.CommitInfo],
comments: Seq[gitbucket.core.model.Comment],
isManageable: Boolean,
repository: gitbucket.core.service.RepositoryService.RepositoryInfo)(implicit context: gitbucket.core.controller.Context)
@gitbucket.core.pulls.html.menu("files", issue, pullreq, commits, comments, isManageable, repository) {
@gitbucket.core.helper.html.diff(
diffs,
repository,
commits.headOption.map(_.id),
commits.lastOption.map(_.id),
true,
Some(pullreq.issueId),
isManageable,
true
)
}

View File

@@ -0,0 +1,99 @@
@(active: String,
issue: gitbucket.core.model.Issue,
pullreq: gitbucket.core.model.PullRequest,
commits: Seq[gitbucket.core.util.JGitUtil.CommitInfo],
comments: Seq[gitbucket.core.model.Comment],
isManageable: Boolean,
repository: gitbucket.core.service.RepositoryService.RepositoryInfo)(body: => Html)(implicit context: gitbucket.core.controller.Context)
@import gitbucket.core.view.helpers
@import gitbucket.core.model.IssueComment
@gitbucket.core.html.main(s"${issue.title} - Pull request #${issue.issueId} - ${repository.owner}/${repository.name}", Some(repository)) {
@gitbucket.core.html.menu("pulls", repository) {
<div>
<div class="show-title pull-right">
@if(isManageable || context.loginAccount.map(_.userName == issue.openedUserName).getOrElse(false)) {
<a class="btn btn-default" href="#" id="edit">Edit</a>
}
@if(context.loginAccount.isDefined) {
<a class="btn btn-success" href="@helpers.url(repository)/compare">New pull request</a>
}
</div>
<div class="edit-title pull-right" style="display: none;">
<a class="btn btn-success" href="#" id="update">Save</a> <a class="btn btn-default" href="#" id="cancel">
Cancel</a>
</div>
<h1 class="body-title">
<span class="show-title">
<span id="show-title">@issue.title</span>
<span class="muted">#@issue.issueId</span>
</span>
<span class="edit-title" style="display: none;">
<span id="error-edit-title" class="error"></span>
<input type="text" class="form-control" style="width: 700px;" id="edit-title" value="@issue.title"/>
</span>
</h1>
</div>
<div style="margin-bottom: 15px">
@if(issue.closed) {
@comments.flatMap @{
case comment: IssueComment => Some(comment)
case _ => None
}.find(_.action == "merge").map { comment =>
<span class="label label-info issue-status">Merged</span>
<span class="muted">
@helpers.user(comment.commentedUserName, styleClass = "username strong")
merged @commits.size @helpers.plural(commits.size, "commit")
into <code>@pullreq.userName:@pullreq.branch</code> from <code>@pullreq.requestUserName
:@pullreq.requestBranch</code>
@gitbucket.core.helper.html.datetimeago(comment.registeredDate)
</span>
}.getOrElse {
<span class="label label-important issue-status">Closed</span>
<span class="muted">
@helpers.user(issue.openedUserName, styleClass = "username strong")
wants to merge @commits.size @helpers.plural(commits.size, "commit")
into <code>@pullreq.userName:@pullreq.branch</code> from <code>@pullreq.requestUserName
:@pullreq.requestBranch</code>
</span>
}
} else {
<span class="label label-success issue-status">Open</span>
<span class="muted">
@helpers.user(issue.openedUserName, styleClass = "username strong")
wants to merge @commits.size @helpers.plural(commits.size, "commit")
into <code>@pullreq.userName:@pullreq.branch</code> from <code>@pullreq.requestUserName
:@pullreq.requestBranch</code>
</span>
}
</div>
<ul class="nav nav-tabs fill-width" id="pullreq-tab">
<li @if(active=="conversation"){class="active"}><a href="@helpers.url(repository)/pull/@issue.issueId">Conversation</a></li>
<li @if(active=="commits"){class="active"}><a href="@helpers.url(repository)/pull/@issue.issueId/commits">Commits</a></li>
<li @if(active=="files"){class="active"}><a href="@helpers.url(repository)/pull/@issue.issueId/files">Files Changed</a></li>
</ul>
<div class="tab-content fill-width" style="padding-top: 20px;">
@body
@*
<div class="tab-pane" id="conversation">
@flash.get("error").map { error =>
<div class="alert alert-error">@error</div>
}
@flash.get("info").map { info =>
<div class="alert alert-info">@info</div>
}
@gitbucket.core.pulls.html.conversation(issue, pullreq, commits, comments, issueLabels, collaborators, milestones, priorities, labels, isEditable, isManageable, isManageableForkedRepository, repository, forkedRepository)
</div>
<div class="tab-pane" id="commits">
@if(commits.nonEmpty) {
@gitbucket.core.pulls.html.commits(dayByDayCommits, repository)
}
</div>
<div class="tab-pane" id="files">
@if(commits.nonEmpty) {
@gitbucket.core.helper.html.diff(diffs, repository, commits.headOption.map(_.id), commits.lastOption.map(_.id), true, Some(pullreq.issueId), isManageable, true)
}
</div>
*@
</div>
}
}

View File

@@ -17,6 +17,7 @@
@import gitbucket.core.view.helpers
@import gitbucket.core.model.IssueComment
@import gitbucket.core.model.CommitComment
@*
@gitbucket.core.html.main(s"${issue.title} - Pull request #${issue.issueId} - ${repository.owner}/${repository.name}", Some(repository)){
@gitbucket.core.html.menu("pulls", repository){
@defining(dayByDayCommits.flatten){ commits =>
@@ -157,3 +158,4 @@ $(function(){
});
});
</script>
*@

View File

@@ -85,10 +85,10 @@
$tr.after(tmp);
}
$('#comment-list').append(data);
if (typeof $('#show-notes')[0] !== 'undefined' && !$('#show-notes')[0].checked) {
$('#comment-list').children('.inline-comment').hide();
}
// $('#comment-list').append(data);
// if (typeof $('#show-notes')[0] !== 'undefined' && !$('#show-notes')[0].checked) {
// $('#comment-list').children('.inline-comment').hide();
// }
}).fail(function(req) {
$('.btn-inline-comment').removeAttr('disabled');
$('#error-content', $form).html($.parseJSON(req.responseText).content);