Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 45 additions & 20 deletions models/issue_comment.go
Original file line number Diff line number Diff line change
@@ -979,7 +979,7 @@ func (opts *FindCommentsOptions) toConds() builder.Cond {
if opts.Type != CommentTypeUnknown {
cond = cond.And(builder.Eq{"comment.type": opts.Type})
}
if opts.Line > 0 {
if opts.Line != 0 {
cond = cond.And(builder.Eq{"comment.line": opts.Line})
}
if len(opts.TreePath) > 0 {
@@ -1078,18 +1078,35 @@ func fetchCodeCommentsByReview(e Engine, issue *Issue, currentUser *User, review
if review == nil {
review = &Review{ID: 0}
}
//Find comments
opts := FindCommentsOptions{
Type: CommentTypeCode,
IssueID: issue.ID,
ReviewID: review.ID,
}

comments, err := findCodeComments(e, opts, issue, currentUser, review)
if err != nil {
return nil, err
}

for _, comment := range comments {
if pathToLineToComment[comment.TreePath] == nil {
pathToLineToComment[comment.TreePath] = make(map[int64][]*Comment)
}
pathToLineToComment[comment.TreePath][comment.Line] = append(pathToLineToComment[comment.TreePath][comment.Line], comment)
}
return pathToLineToComment, nil
}

func findCodeComments(e Engine, opts FindCommentsOptions, issue *Issue, currentUser *User, review *Review) ([]*Comment, error) {
var comments []*Comment
if review == nil {
review = &Review{ID: 0}
}
conds := opts.toConds()
if review.ID == 0 {
conds = conds.And(builder.Eq{"invalidated": false})
}

var comments []*Comment
if err := e.Where(conds).
Asc("comment.created_unix").
Asc("comment.id").
@@ -1117,7 +1134,19 @@ func fetchCodeCommentsByReview(e Engine, issue *Issue, currentUser *User, review
return nil, err
}

n := 0
for _, comment := range comments {
if re, ok := reviews[comment.ReviewID]; ok && re != nil {
// If the review is pending only the author can see the comments (except if the review is set)
if review.ID == 0 && re.Type == ReviewTypePending &&
(currentUser == nil || currentUser.ID != re.ReviewerID) {
continue
}
comment.Review = re
}
comments[n] = comment
n++

if err := comment.LoadResolveDoer(); err != nil {
return nil, err
}
@@ -1126,25 +1155,21 @@ func fetchCodeCommentsByReview(e Engine, issue *Issue, currentUser *User, review
return nil, err
}

if re, ok := reviews[comment.ReviewID]; ok && re != nil {
// If the review is pending only the author can see the comments (except the review is set)
if review.ID == 0 {
if re.Type == ReviewTypePending &&
(currentUser == nil || currentUser.ID != re.ReviewerID) {
continue
}
}
comment.Review = re
}

comment.RenderedContent = string(markdown.Render([]byte(comment.Content), issue.Repo.Link(),
issue.Repo.ComposeMetas()))
if pathToLineToComment[comment.TreePath] == nil {
pathToLineToComment[comment.TreePath] = make(map[int64][]*Comment)
}
pathToLineToComment[comment.TreePath][comment.Line] = append(pathToLineToComment[comment.TreePath][comment.Line], comment)
}
return pathToLineToComment, nil
return comments[:n], nil
}

// FetchCodeCommentsByLine fetches the code comments for a given treePath and line number
func FetchCodeCommentsByLine(issue *Issue, currentUser *User, treePath string, line int64) ([]*Comment, error) {
opts := FindCommentsOptions{
Type: CommentTypeCode,
IssueID: issue.ID,
TreePath: treePath,
Line: line,
}
return findCodeComments(x, opts, issue, currentUser, nil)
}

// FetchCodeComments will return a 2d-map: ["Path"]["Line"] = Comments at line
1 change: 1 addition & 0 deletions modules/auth/repo_form.go
Original file line number Diff line number Diff line change
@@ -548,6 +548,7 @@ func (f *MergePullRequestForm) Validate(ctx *macaron.Context, errs binding.Error

// CodeCommentForm form for adding code comments for PRs
type CodeCommentForm struct {
Origin string `binding:"Required;In(timeline,diff)"`
Content string `binding:"Required"`
Side string `binding:"Required;In(previous,proposed)"`
Line int64
62 changes: 62 additions & 0 deletions routers/repo/pull_review.go
Original file line number Diff line number Diff line change
@@ -9,11 +9,40 @@ import (

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
pull_service "code.gitea.io/gitea/services/pull"
)

const (
tplConversation base.TplName = "repo/diff/conversation"
tplNewComment base.TplName = "repo/diff/new_comment"
)

// RenderNewCodeCommentForm will render the form for creating a new review comment
func RenderNewCodeCommentForm(ctx *context.Context) {
issue := GetActionIssue(ctx)
if !issue.IsPull {
return
}
currentReview, err := models.GetCurrentReview(ctx.User, issue)
if err != nil && !models.IsErrReviewNotExist(err) {
ctx.ServerError("GetCurrentReview", err)
return
}
ctx.Data["PageIsPullFiles"] = true
ctx.Data["Issue"] = issue
ctx.Data["CurrentReview"] = currentReview
pullHeadCommitID, err := ctx.Repo.GitRepo.GetRefCommitID(issue.PullRequest.GetGitRefName())
if err != nil {
ctx.ServerError("GetRefCommitID", err)
return
}
ctx.Data["AfterCommitID"] = pullHeadCommitID
ctx.HTML(200, tplNewComment)
}

// CreateCodeComment will create a code comment including an pending review if required
func CreateCodeComment(ctx *context.Context, form auth.CodeCommentForm) {
issue := GetActionIssue(ctx)
@@ -58,11 +87,17 @@ func CreateCodeComment(ctx *context.Context, form auth.CodeCommentForm) {
}

log.Trace("Comment created: %-v #%d[%d] Comment[%d]", ctx.Repo.Repository, issue.Index, issue.ID, comment.ID)

if form.Origin == "diff" {
renderConversation(ctx, comment)
return
}
ctx.Redirect(comment.HTMLURL())
}

// UpdateResolveConversation add or remove an Conversation resolved mark
func UpdateResolveConversation(ctx *context.Context) {
origin := ctx.Query("origin")
action := ctx.Query("action")
commentID := ctx.QueryInt64("comment_id")

@@ -103,11 +138,38 @@ func UpdateResolveConversation(ctx *context.Context) {
return
}

if origin == "diff" {
renderConversation(ctx, comment)
return
}
ctx.JSON(200, map[string]interface{}{
"ok": true,
})
}

func renderConversation(ctx *context.Context, comment *models.Comment) {
comments, err := models.FetchCodeCommentsByLine(comment.Issue, ctx.User, comment.TreePath, comment.Line)
if err != nil {
ctx.ServerError("FetchCodeCommentsByLine", err)
return
}
ctx.Data["PageIsPullFiles"] = true
ctx.Data["comments"] = comments
ctx.Data["CanMarkConversation"] = true
ctx.Data["Issue"] = comment.Issue
if err = comment.Issue.LoadPullRequest(); err != nil {
ctx.ServerError("comment.Issue.LoadPullRequest", err)
return
}
pullHeadCommitID, err := ctx.Repo.GitRepo.GetRefCommitID(comment.Issue.PullRequest.GetGitRefName())
if err != nil {
ctx.ServerError("GetRefCommitID", err)
return
}
ctx.Data["AfterCommitID"] = pullHeadCommitID
ctx.HTML(200, tplConversation)
}

// SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist
func SubmitReview(ctx *context.Context, form auth.SubmitReviewForm) {
issue := GetActionIssue(ctx)
1 change: 1 addition & 0 deletions routers/routes/macaron.go
Original file line number Diff line number Diff line change
@@ -856,6 +856,7 @@ func RegisterMacaronRoutes(m *macaron.Macaron) {
m.Group("/files", func() {
m.Get("", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.ViewPullFiles)
m.Group("/reviews", func() {
m.Get("/new_comment", repo.RenderNewCodeCommentForm)
m.Post("/comments", bindIgnErr(auth.CodeCommentForm{}), repo.CreateCodeComment)
m.Post("/submit", bindIgnErr(auth.SubmitReviewForm{}), repo.SubmitReview)
}, context.RepoMustNotBeArchived())
37 changes: 17 additions & 20 deletions templates/repo/diff/box.tmpl
Original file line number Diff line number Diff line change
@@ -144,28 +144,25 @@
{{end}}

{{if not $.Repository.IsArchived}}
<div id="pull_review_add_comment" class="hide">
{{template "repo/diff/new_comment" dict "root" .}}
<div class="hide" id="edit-content-form">
<div class="ui comment form">
<div class="ui top attached tabular menu">
<a class="active write item">{{$.i18n.Tr "write"}}</a>
<a class="preview item" data-url="{{$.Repository.APIURL}}/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a>
</div>
<div class="hide" id="edit-content-form">
<div class="ui comment form">
<div class="ui top attached tabular menu">
<a class="active write item">{{$.i18n.Tr "write"}}</a>
<a class="preview item" data-url="{{$.Repository.APIURL}}/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a>
</div>
<div class="ui bottom attached active write tab segment">
<textarea class="review-textarea" tabindex="1" name="content"></textarea>
</div>
<div class="ui bottom attached tab preview segment markdown">
{{$.i18n.Tr "loading"}}
</div>
<div class="text right edit buttons">
<div class="ui basic blue cancel button" tabindex="3">{{.i18n.Tr "repo.issues.cancel"}}</div>
<div class="ui green save button" tabindex="2">{{.i18n.Tr "repo.issues.save"}}</div>
</div>
</div>
<div class="ui bottom attached active write tab segment">
<textarea class="review-textarea" tabindex="1" name="content"></textarea>
</div>
<div class="ui bottom attached tab preview segment markdown">
{{$.i18n.Tr "loading"}}
</div>
<div class="text right edit buttons">
<div class="ui basic blue cancel button" tabindex="3">{{.i18n.Tr "repo.issues.cancel"}}</div>
<div class="ui green save button" tabindex="2">{{.i18n.Tr "repo.issues.save"}}</div>
</div>
{{end}}
</div>
</div>
{{end}}

{{if .IsSplitStyle}}
<script>
3 changes: 2 additions & 1 deletion templates/repo/diff/comment_form.tmpl
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
{{end}}
<form class="ui form {{if $.hidden}}hide comment-form comment-form-reply{{end}}" action="{{$.root.Issue.HTMLURL}}/files/reviews/comments" method="post">
{{$.root.CsrfTokenHtml}}
<input type="hidden" name="origin" value="{{if $.root.PageIsPullFiles}}diff{{else}}timeline{{end}}">
<input type="hidden" name="latest_commit_id" value="{{$.root.AfterCommitID}}"/>
<input type="hidden" name="side" value="{{if $.Side}}{{$.Side}}{{end}}">
<input type="hidden" name="line" value="{{if $.Line}}{{$.Line}}{{end}}">
@@ -29,7 +30,7 @@
<span class="markdown-info">{{svg "octicon-markdown"}} {{$.root.i18n.Tr "repo.diff.comment.markdown_info"}}</span>
<div class="ui right">
{{if $.reply}}
<button class="ui submit green tiny button btn-reply" onclick="window.submitReply(this);">{{$.root.i18n.Tr "repo.diff.comment.reply"}}</button>
<button class="ui submit green tiny button btn-reply" type="submit">{{$.root.i18n.Tr "repo.diff.comment.reply"}}</button>
<input type="hidden" name="reply" value="{{$.reply}}">
{{else}}
{{if $.root.CurrentReview}}
4 changes: 2 additions & 2 deletions templates/repo/diff/conversation.tmpl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{{$resolved := (index .comments 0).IsResolved}}
{{$resolveDoer := (index .comments 0).ResolveDoer}}
{{$isNotPending := (not (eq (index .comments 0).Review.Type 0))}}
<div class="conversation-holder">
<div class="conversation-holder" data-path="{{(index .comments 0).TreePath}}" data-side="{{if lt (index .comments 0).Line 0}}left{{else}}right{{end}}" data-idx="{{(index .comments 0).UnsignedLine}}">
{{if $resolved}}
<div class="ui attached header resolved-placeholder">
<span class="ui grey text left"><b>{{$resolveDoer.Name}}</b> {{$.i18n.Tr "repo.issues.review.resolved_by"}}</span>
@@ -23,7 +23,7 @@
</div>
{{template "repo/diff/comment_form_datahandler" dict "hidden" true "reply" (index .comments 0).ReviewID "root" $ "comment" (index .comments 0)}}
{{if and $.CanMarkConversation $isNotPending}}
<button class="ui icon tiny button resolve-conversation" data-action="{{if not $resolved}}Resolve{{else}}UnResolve{{end}}" data-comment-id="{{(index .comments 0).ID}}" data-update-url="{{$.RepoLink}}/issues/resolve_conversation" >
<button class="ui icon tiny button resolve-conversation" data-origin="diff" data-action="{{if not $resolved}}Resolve{{else}}UnResolve{{end}}" data-comment-id="{{(index .comments 0).ID}}" data-update-url="{{$.RepoLink}}/issues/resolve_conversation" >
{{if $resolved}}
{{$.i18n.Tr "repo.issues.review.un_resolve_conversation"}}
{{else}}
6 changes: 4 additions & 2 deletions templates/repo/diff/new_comment.tmpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<div class="field comment-code-cloud">
{{template "repo/diff/comment_form_datahandler" .}}
<div class="conversation-holder">
<div class="field comment-code-cloud">
{{template "repo/diff/comment_form_datahandler" .}}
</div>
</div>
8 changes: 4 additions & 4 deletions templates/repo/diff/section_split.tmpl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{{$file := .file}}
{{range $j, $section := $file.Sections}}
{{range $k, $line := $section.Lines}}
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}">
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}" data-line-type="{{DiffLineTypeToStr .GetType}}">
{{if eq .GetType 4}}
<td class="lines-num lines-num-old">
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }}
@@ -24,14 +24,14 @@
{{else}}
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $file.Name}}L{{$line.LeftIdx}}{{end}}"></span></td>
<td class="lines-type-marker lines-type-marker-old">{{if $line.LeftIdx}}<span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td>
<td class="lines-code lines-code-old halfwidth">{{if and $.root.SignedUserID $line.CanComment $.root.PageIsPullFiles (not (eq .GetType 2))}}<a class="ui primary button add-code-comment add-code-comment-left" data-path="{{$file.Name}}" data-side="left" data-idx="{{$line.LeftIdx}}">{{svg "octicon-plus"}}</a>{{end}}<code class="code-inner">{{if $line.LeftIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</code></td>
<td class="lines-code lines-code-old halfwidth">{{if and $.root.SignedUserID $.root.PageIsPullFiles (not (eq .GetType 2))}}<a class="ui primary button add-code-comment add-code-comment-left{{if (not $line.CanComment)}} invisible{{end}}" data-path="{{$file.Name}}" data-side="left" data-idx="{{$line.LeftIdx}}" data-new-comment-url="{{$.root.Issue.HTMLURL}}/files/reviews/new_comment">{{svg "octicon-plus"}}</a>{{end}}<code class="code-inner">{{if $line.LeftIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</code></td>
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}"></span></td>
<td class="lines-type-marker lines-type-marker-new">{{if $line.RightIdx}}<span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td>
<td class="lines-code lines-code-new halfwidth">{{if and $.root.SignedUserID $line.CanComment $.root.PageIsPullFiles (not (eq .GetType 3))}}<a class="ui primary button add-code-comment add-code-comment-right" data-path="{{$file.Name}}" data-side="right" data-idx="{{$line.RightIdx}}">{{svg "octicon-plus"}}</a>{{end}}<code class="code-inner">{{if $line.RightIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</code></td>
<td class="lines-code lines-code-new halfwidth">{{if and $.root.SignedUserID $.root.PageIsPullFiles (not (eq .GetType 3))}}<a class="ui primary button add-code-comment add-code-comment-right{{if (not $line.CanComment)}} invisible{{end}}" data-path="{{$file.Name}}" data-side="right" data-idx="{{$line.RightIdx}}" data-new-comment-url="{{$.root.Issue.HTMLURL}}/files/reviews/new_comment">{{svg "octicon-plus"}}</a>{{end}}<code class="code-inner">{{if $line.RightIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</code></td>
{{end}}
</tr>
{{if gt (len $line.Comments) 0}}
<tr class="add-code-comment">
<tr class="add-comment" data-line-type="{{DiffLineTypeToStr .GetType}}">
<td class="lines-num"></td>
<td class="lines-type-marker"></td>
<td class="add-comment-left">
6 changes: 3 additions & 3 deletions templates/repo/diff/section_unified.tmpl
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
{{range $j, $section := $file.Sections}}
{{range $k, $line := $section.Lines}}
{{if or $.root.AfterCommitID (ne .GetType 4)}}
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}">
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}" data-line-type="{{DiffLineTypeToStr .GetType}}">
{{if eq .GetType 4}}
<td colspan="2" class="lines-num">
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }}
@@ -29,11 +29,11 @@
{{if eq .GetType 4}}
<td class="chroma lines-code blob-hunk"><code class="code-inner">{{$section.GetComputedInlineDiffFor $line}}</code></td>
{{else}}
<td class="chroma lines-code{{if (not $line.RightIdx)}} lines-code-old{{end}}">{{if and $.root.SignedUserID $line.CanComment $.root.PageIsPullFiles}}<a class="ui primary button add-code-comment add-code-comment-{{if $line.RightIdx}}right{{else}}left{{end}}" data-path="{{$file.Name}}" data-side="{{if $line.RightIdx}}right{{else}}left{{end}}" data-idx="{{if $line.RightIdx}}{{$line.RightIdx}}{{else}}{{$line.LeftIdx}}{{end}}">{{svg "octicon-plus"}}</a>{{end}}<code class="code-inner">{{$section.GetComputedInlineDiffFor $line}}</code></td>
<td class="chroma lines-code{{if (not $line.RightIdx)}} lines-code-old{{end}}">{{if and $.root.SignedUserID $.root.PageIsPullFiles}}<a class="ui primary button add-code-comment add-code-comment-{{if $line.RightIdx}}right{{else}}left{{end}}{{if (not $line.CanComment)}} invisible{{end}}" data-path="{{$file.Name}}" data-side="{{if $line.RightIdx}}right{{else}}left{{end}}" data-idx="{{if $line.RightIdx}}{{$line.RightIdx}}{{else}}{{$line.LeftIdx}}{{end}}" data-new-comment-url="{{$.root.Issue.HTMLURL}}/files/reviews/new_comment">{{svg "octicon-plus"}}</a>{{end}}<code class="code-inner">{{$section.GetComputedInlineDiffFor $line}}</code></td>
{{end}}
</tr>
{{if gt (len $line.Comments) 0}}
<tr>
<tr class="add-comment" data-line-type="{{DiffLineTypeToStr .GetType}}">
<td colspan="2" class="lines-num"></td>
<td class="add-comment-left add-comment-right" colspan="2">
{{template "repo/diff/conversation" mergeinto $.root "comments" $line.Comments}}
2 changes: 1 addition & 1 deletion templates/repo/issue/view_content/comments.tmpl
Original file line number Diff line number Diff line change
@@ -530,7 +530,7 @@
{{template "repo/diff/comment_form_datahandler" dict "hidden" true "reply" (index $comms 0).ReviewID "root" $ "comment" (index $comms 0)}}

{{if and $.CanMarkConversation $isNotPending}}
<button class="ui tiny button resolve-conversation" data-action="{{if not $resolved}}Resolve{{else}}UnResolve{{end}}" data-comment-id="{{(index $comms 0).ID}}" data-update-url="{{$.RepoLink}}/issues/resolve_conversation" >
<button class="ui tiny button resolve-conversation" data-origin="timeline" data-action="{{if not $resolved}}Resolve{{else}}UnResolve{{end}}" data-comment-id="{{(index $comms 0).ID}}" data-update-url="{{$.RepoLink}}/issues/resolve_conversation" >
{{if $resolved}}
{{$.i18n.Tr "repo.issues.review.un_resolve_conversation"}}
{{else}}
102 changes: 63 additions & 39 deletions web_src/js/index.js
Original file line number Diff line number Diff line change
@@ -907,7 +907,7 @@ async function initRepository() {
});

// Quote reply
$('.quote-reply').on('click', function (event) {
$(document).on('click', '.quote-reply', function (event) {
$(this).closest('.dropdown').find('.menu').toggle('visible');
const target = $(this).data('target');
const quote = $(`#comment-${target}`).text().replace(/\n/g, '\n> ');
@@ -933,7 +933,7 @@ async function initRepository() {
});

// Edit issue or comment content
$('.edit-content').on('click', async function (event) {
$(document).on('click', '.edit-content', async function (event) {
$(this).closest('.dropdown').find('.menu').toggle('visible');
const $segment = $(this).closest('.header').next();
const $editContentZone = $segment.find('.edit-content-zone');
@@ -1096,7 +1096,7 @@ async function initRepository() {
});

// Delete comment
$('.delete-comment').on('click', function () {
$(document).on('click', '.delete-comment', function () {
const $this = $(this);
if (window.confirm($this.data('locale'))) {
$.post($this.data('url'), {
@@ -1105,6 +1105,15 @@ async function initRepository() {
const $conversationHolder = $this.closest('.conversation-holder');
$(`#${$this.data('comment-id')}`).remove();
if ($conversationHolder.length && !$conversationHolder.find('.comment').length) {
const path = $conversationHolder.data('path');
const side = $conversationHolder.data('side');
const idx = $conversationHolder.data('idx');
const lineType = $conversationHolder.closest('tr').data('line-type');
if (lineType === 'same') {
$(`a.add-code-comment[data-path="${path}"][data-idx="${idx}"]`).removeClass('invisible');
} else {
$(`a.add-code-comment[data-path="${path}"][data-side="${side}"][data-idx="${idx}"]`).removeClass('invisible');
}
$conversationHolder.remove();
}
});
@@ -1235,7 +1244,7 @@ function initPullRequestReview() {
}
}

$('.show-outdated').on('click', function (e) {
$(document).on('click', '.show-outdated', function (e) {
e.preventDefault();
const id = $(this).data('comment');
$(this).addClass('hide');
@@ -1244,7 +1253,7 @@ function initPullRequestReview() {
$(`#hide-outdated-${id}`).removeClass('hide');
});

$('.hide-outdated').on('click', function (e) {
$(document).on('click', '.hide-outdated', function (e) {
e.preventDefault();
const id = $(this).data('comment');
$(this).addClass('hide');
@@ -1253,7 +1262,7 @@ function initPullRequestReview() {
$(`#show-outdated-${id}`).removeClass('hide');
});

$('button.comment-form-reply').on('click', function (e) {
$(document).on('click', 'button.comment-form-reply', function (e) {
e.preventDefault();
$(this).hide();
const form = $(this).parent().find('.comment-form');
@@ -1284,26 +1293,21 @@ function initPullRequestReview() {
$(this).closest('.menu').toggle('visible');
});

$('.add-code-comment').on('click', function (e) {
$('a.add-code-comment').on('click', async function (e) {
if ($(e.target).hasClass('btn-add-single')) return; // https://github.com/go-gitea/gitea/issues/4745
e.preventDefault();

const isSplit = $(this).closest('.code-diff').hasClass('code-diff-split');
const side = $(this).data('side');
const idx = $(this).data('idx');
const path = $(this).data('path');
const form = $('#pull_review_add_comment').html();
const tr = $(this).closest('tr');

const oldLineNum = tr.find('.lines-num-old').data('line-num');
const newLineNum = tr.find('.lines-num-new').data('line-num');
const addCommentKey = `${oldLineNum}|${newLineNum}`;
if (document.querySelector(`[data-add-comment-key="${addCommentKey}"]`)) return; // don't add same comment box twice
const lineType = tr.data('line-type');

let ntr = tr.next();
if (!ntr.hasClass('add-comment')) {
ntr = $(`
<tr class="add-comment" data-add-comment-key="${addCommentKey}">
<tr class="add-comment" data-line-type="${lineType}">
${isSplit ? `
<td class="lines-num"></td>
<td class="lines-type-marker"></td>
@@ -1312,8 +1316,7 @@ function initPullRequestReview() {
<td class="lines-type-marker"></td>
<td class="add-comment-right"></td>
` : `
<td class="lines-num"></td>
<td class="lines-num"></td>
<td colspan="2" class="lines-num"></td>
<td class="add-comment-left add-comment-right" colspan="2"></td>
`}
</tr>`);
@@ -1322,21 +1325,20 @@ function initPullRequestReview() {

const td = ntr.find(`.add-comment-${side}`);
let commentCloud = td.find('.comment-code-cloud');
if (commentCloud.length === 0) {
td.html(form);
if (commentCloud.length === 0 && !ntr.find('button[name="is_review"]').length) {
const data = await $.get($(this).data('new-comment-url'));
td.html(data);
commentCloud = td.find('.comment-code-cloud');
assingMenuAttributes(commentCloud.find('.menu'));

td.find("input[name='line']").val(idx);
td.find("input[name='side']").val(side === 'left' ? 'previous' : 'proposed');
td.find("input[name='path']").val(path);
const $textarea = commentCloud.find('textarea');
attachTribute($textarea.get(), {mentions: true, emoji: true});
const $simplemde = setCommentSimpleMDE($textarea);
$textarea.focus();
$simplemde.codemirror.focus();
}
const $textarea = commentCloud.find('textarea');
attachTribute($textarea.get(), {mentions: true, emoji: true});

const $simplemde = setCommentSimpleMDE($textarea);
$textarea.focus();
$simplemde.codemirror.focus();
});
}

@@ -2497,17 +2499,24 @@ $(document).ready(async () => {
$(e).trigger('click');
});

$('.resolve-conversation').on('click', function (e) {
$(document).on('click', '.resolve-conversation', async function (e) {
e.preventDefault();
const id = $(this).data('comment-id');
const comment_id = $(this).data('comment-id');
const origin = $(this).data('origin');
const action = $(this).data('action');
const url = $(this).data('update-url');

$.post(url, {
_csrf: csrf,
action,
comment_id: id,
}).then(reload);
const data = await $.post(url, {_csrf: csrf, origin, action, comment_id});

if ($(this).closest('.conversation-holder').length) {
const conversation = $(data);
$(this).closest('.conversation-holder').replaceWith(conversation);
conversation.find('.dropdown').dropdown();
initReactionSelector(conversation);
initClipboard();
} else {
reload();
}
});

buttonsClickOnEnter();
@@ -3626,6 +3635,28 @@ function initIssueList() {
}
});
}

$(document).on('click', 'button[name="is_review"]', (e) => {
$(e.target).closest('form').append('<input type="hidden" name="is_review" value="true">');
});

$(document).on('submit', '.conversation-holder form', async (e) => {
e.preventDefault();
const form = $(e.target);
const newConversationHolder = $(await $.post(form.attr('action'), form.serialize()));
const {path, side, idx} = newConversationHolder.data();

form.closest('.conversation-holder').replaceWith(newConversationHolder);
if (form.closest('tr').data('line-type') === 'same') {
$(`a.add-code-comment[data-path="${path}"][data-idx="${idx}"]`).addClass('invisible');
} else {
$(`a.add-code-comment[data-path="${path}"][data-side="${side}"][data-idx="${idx}"]`).addClass('invisible');
}
newConversationHolder.find('.dropdown').dropdown();
initReactionSelector(newConversationHolder);
initClipboard();
});

window.cancelCodeComment = function (btn) {
const form = $(btn).closest('form');
if (form.length > 0 && form.hasClass('comment-form')) {
@@ -3636,13 +3667,6 @@ window.cancelCodeComment = function (btn) {
}
};

window.submitReply = function (btn) {
const form = $(btn).closest('form');
if (form.length > 0 && form.hasClass('comment-form')) {
form.trigger('submit');
}
};

window.onOAuthLoginClick = function () {
const oauthLoader = $('#oauth2-login-loader');
const oauthNav = $('#oauth2-login-navigator');