Add a way to mark Conversation (code comment) resolved (#11037)
* Add a way to mark Conversation (code comment) resolved mark Conversation is a way to mark a Conversation is stale or be solved. when it's marked as stale, will be hided like stale. all Pull Request writer , Offical Reviewers and poster can add or remove Conversation resolved mark. Signed-off-by: a1012112796 <1012112796@qq.com> * fix lint * Apply suggestions from code review * Add ResolveDoer * fix ui Co-Authored-By: Lauris BH <lauris@nix.lv> Co-Authored-By: 6543 <6543@obermui.de> * change IsResolved to an function Add permission check in UpdateResolveConversation * Apply suggestions from code review * change return error for permisson check * add default message for deleted user * get issue message from comment * add migration for ``ResolveDoerID`` column another change: * block mark pending review as resolved because it's not necessary Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com> * change button color * resolve button size * fix code style * remove unusefull code Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com> Co-authored-by: Lauris BH <lauris@nix.lv> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									38d5f88a81
								
							
						
					
					
						commit
						1b86f174ce
					
				
					 13 changed files with 301 additions and 9 deletions
				
			
		|  | @ -122,6 +122,8 @@ type Comment struct { | |||
| 	AssigneeID       int64 | ||||
| 	RemovedAssignee  bool | ||||
| 	Assignee         *User `xorm:"-"` | ||||
| 	ResolveDoerID    int64 | ||||
| 	ResolveDoer      *User `xorm:"-"` | ||||
| 	OldTitle         string | ||||
| 	NewTitle         string | ||||
| 	OldRef           string | ||||
|  | @ -420,6 +422,26 @@ func (c *Comment) LoadAssigneeUser() error { | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // LoadResolveDoer if comment.Type is CommentTypeCode and ResolveDoerID not zero, then load resolveDoer
 | ||||
| func (c *Comment) LoadResolveDoer() (err error) { | ||||
| 	if c.ResolveDoerID == 0 || c.Type != CommentTypeCode { | ||||
| 		return nil | ||||
| 	} | ||||
| 	c.ResolveDoer, err = getUserByID(x, c.ResolveDoerID) | ||||
| 	if err != nil { | ||||
| 		if IsErrUserNotExist(err) { | ||||
| 			c.ResolveDoer = NewGhostUser() | ||||
| 			err = nil | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // IsResolved check if an code comment is resolved
 | ||||
| func (c *Comment) IsResolved() bool { | ||||
| 	return c.ResolveDoerID != 0 && c.Type == CommentTypeCode | ||||
| } | ||||
| 
 | ||||
| // LoadDepIssueDetails loads Dependent Issue Details
 | ||||
| func (c *Comment) LoadDepIssueDetails() (err error) { | ||||
| 	if c.DependentIssueID <= 0 || c.DependentIssue != nil { | ||||
|  | @ -943,7 +965,12 @@ func fetchCodeCommentsByReview(e Engine, issue *Issue, currentUser *User, review | |||
| 	if err := e.In("id", ids).Find(&reviews); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	for _, comment := range comments { | ||||
| 		if err := comment.LoadResolveDoer(); err != nil { | ||||
| 			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 { | ||||
|  |  | |||
|  | @ -208,6 +208,8 @@ var migrations = []Migration{ | |||
| 	NewMigration("Add CommitsAhead and CommitsBehind Column to PullRequest Table", addCommitDivergenceToPulls), | ||||
| 	// v137 -> v138
 | ||||
| 	NewMigration("Add Branch Protection Block Outdated Branch", addBlockOnOutdatedBranch), | ||||
| 	// v138 -> v139
 | ||||
| 	NewMigration("Add ResolveDoerID to Comment table", addResolveDoerIDCommentColumn), | ||||
| } | ||||
| 
 | ||||
| // GetCurrentDBVersion returns the current db version
 | ||||
|  |  | |||
							
								
								
									
										22
									
								
								models/migrations/v138.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								models/migrations/v138.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | |||
| // Copyright 2020 The Gitea Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a MIT-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package migrations | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"xorm.io/xorm" | ||||
| ) | ||||
| 
 | ||||
| func addResolveDoerIDCommentColumn(x *xorm.Engine) error { | ||||
| 	type Comment struct { | ||||
| 		ResolveDoerID int64 | ||||
| 	} | ||||
| 
 | ||||
| 	if err := x.Sync2(new(Comment)); err != nil { | ||||
| 		return fmt.Errorf("Sync2: %v", err) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | @ -5,6 +5,7 @@ | |||
| package models | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"code.gitea.io/gitea/modules/timeutil" | ||||
|  | @ -594,3 +595,62 @@ func RemoveRewiewRequest(issue *Issue, reviewer *User, doer *User) (comment *Com | |||
| 
 | ||||
| 	return comment, sess.Commit() | ||||
| } | ||||
| 
 | ||||
| // MarkConversation Add or remove Conversation mark for a code comment
 | ||||
| func MarkConversation(comment *Comment, doer *User, isResolve bool) (err error) { | ||||
| 	if comment.Type != CommentTypeCode { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	if isResolve { | ||||
| 		if comment.ResolveDoerID != 0 { | ||||
| 			return nil | ||||
| 		} | ||||
| 
 | ||||
| 		if _, err = x.Exec("UPDATE `comment` SET resolve_doer_id=? WHERE id=?", doer.ID, comment.ID); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} else { | ||||
| 		if comment.ResolveDoerID == 0 { | ||||
| 			return nil | ||||
| 		} | ||||
| 
 | ||||
| 		if _, err = x.Exec("UPDATE `comment` SET resolve_doer_id=? WHERE id=?", 0, comment.ID); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // CanMarkConversation  Add or remove Conversation mark for a code comment permission check
 | ||||
| // the PR writer , offfcial reviewer and poster can do it
 | ||||
| func CanMarkConversation(issue *Issue, doer *User) (permResult bool, err error) { | ||||
| 	if doer == nil || issue == nil { | ||||
| 		return false, fmt.Errorf("issue or doer is nil") | ||||
| 	} | ||||
| 
 | ||||
| 	if doer.ID != issue.PosterID { | ||||
| 		if err = issue.LoadRepo(); err != nil { | ||||
| 			return false, err | ||||
| 		} | ||||
| 
 | ||||
| 		perm, err := GetUserRepoPermission(issue.Repo, doer) | ||||
| 		if err != nil { | ||||
| 			return false, err | ||||
| 		} | ||||
| 
 | ||||
| 		permResult = perm.CanAccess(AccessModeWrite, UnitTypePullRequests) | ||||
| 		if !permResult { | ||||
| 			if permResult, err = IsOfficialReviewer(issue, doer); err != nil { | ||||
| 				return false, err | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if !permResult { | ||||
| 			return false, nil | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return true, nil | ||||
| } | ||||
|  |  | |||
|  | @ -1067,6 +1067,11 @@ issues.review.review = Review | |||
| issues.review.reviewers = Reviewers | ||||
| issues.review.show_outdated = Show outdated | ||||
| issues.review.hide_outdated = Hide outdated | ||||
| issues.review.show_resolved = Show resolved | ||||
| issues.review.hide_resolved = Hide resolved | ||||
| issues.review.resolve_conversation = Resolve conversation | ||||
| issues.review.un_resolve_conversation = Unresolve conversation | ||||
| issues.review.resolved_by = marked this conversation as resolved | ||||
| issues.assignee.error = Not all assignees was added due to an unexpected error. | ||||
| 
 | ||||
| pulls.desc = Enable pull requests and code reviews. | ||||
|  |  | |||
|  | @ -990,6 +990,11 @@ func ViewIssue(ctx *context.Context) { | |||
| 				ctx.ServerError("Review.LoadCodeComments", err) | ||||
| 				return | ||||
| 			} | ||||
| 
 | ||||
| 			if err = comment.LoadResolveDoer(); err != nil { | ||||
| 				ctx.ServerError("LoadResolveDoer", err) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -1033,6 +1038,11 @@ func ViewIssue(ctx *context.Context) { | |||
| 				ctx.ServerError("IsUserAllowedToMerge", err) | ||||
| 				return | ||||
| 			} | ||||
| 
 | ||||
| 			if ctx.Data["CanMarkConversation"], err = models.CanMarkConversation(issue, ctx.User); err != nil { | ||||
| 				ctx.ServerError("CanMarkConversation", err) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		prUnit, err := repo.GetUnit(models.UnitTypePullRequests) | ||||
|  |  | |||
|  | @ -624,6 +624,13 @@ func ViewPullFiles(ctx *context.Context) { | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if ctx.IsSigned && ctx.User != nil { | ||||
| 		if ctx.Data["CanMarkConversation"], err = models.CanMarkConversation(issue, ctx.User); err != nil { | ||||
| 			ctx.ServerError("CanMarkConversation", err) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	setImageCompareContext(ctx, baseCommit, commit) | ||||
| 	setPathsCompareContext(ctx, baseCommit, commit, headTarget) | ||||
| 
 | ||||
|  |  | |||
|  | @ -61,6 +61,53 @@ func CreateCodeComment(ctx *context.Context, form auth.CodeCommentForm) { | |||
| 	ctx.Redirect(comment.HTMLURL()) | ||||
| } | ||||
| 
 | ||||
| // UpdateResolveConversation add or remove an Conversation resolved mark
 | ||||
| func UpdateResolveConversation(ctx *context.Context) { | ||||
| 	action := ctx.Query("action") | ||||
| 	commentID := ctx.QueryInt64("comment_id") | ||||
| 
 | ||||
| 	comment, err := models.GetCommentByID(commentID) | ||||
| 	if err != nil { | ||||
| 		ctx.ServerError("GetIssueByID", err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if err = comment.LoadIssue(); err != nil { | ||||
| 		ctx.ServerError("comment.LoadIssue", err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	var permResult bool | ||||
| 	if permResult, err = models.CanMarkConversation(comment.Issue, ctx.User); err != nil { | ||||
| 		ctx.ServerError("CanMarkConversation", err) | ||||
| 		return | ||||
| 	} | ||||
| 	if !permResult { | ||||
| 		ctx.Error(403) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if !comment.Issue.IsPull { | ||||
| 		ctx.Error(400) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if action == "Resolve" || action == "UnResolve" { | ||||
| 		err = models.MarkConversation(comment, ctx.User, action == "Resolve") | ||||
| 		if err != nil { | ||||
| 			ctx.ServerError("MarkConversation", err) | ||||
| 			return | ||||
| 		} | ||||
| 	} else { | ||||
| 		ctx.Error(400) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.JSON(200, map[string]interface{}{ | ||||
| 		"ok": true, | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| // 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) | ||||
|  |  | |||
|  | @ -739,6 +739,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| 			m.Post("/assignee", reqRepoIssuesOrPullsWriter, repo.UpdateIssueAssignee) | ||||
| 			m.Post("/request_review", reqRepoIssuesOrPullsReader, repo.UpdatePullReviewRequest) | ||||
| 			m.Post("/status", reqRepoIssuesOrPullsWriter, repo.UpdateIssueStatus) | ||||
| 			m.Post("/resolve_conversation", reqRepoIssuesOrPullsReader, repo.UpdateResolveConversation) | ||||
| 		}, context.RepoMustNotBeArchived()) | ||||
| 		m.Group("/comments/:id", func() { | ||||
| 			m.Post("", repo.UpdateCommentContent) | ||||
|  |  | |||
|  | @ -147,32 +147,79 @@ | |||
| 															{{end}} | ||||
| 														</tr> | ||||
| 														{{if gt (len $line.Comments) 0}} | ||||
| 															{{$resolved := (index $line.Comments 0).IsResolved}} | ||||
| 															{{$resolveDoer := (index $line.Comments 0).ResolveDoer}} | ||||
| 															{{$isNotPending := (not (eq (index $line.Comments 0).Review.Type 0))}} | ||||
| 															<tr class="add-code-comment"> | ||||
| 																<td class="lines-num"></td> | ||||
| 																<td class="lines-type-marker"></td> | ||||
| 																<td class="add-comment-left"> | ||||
| 																	{{if and $resolved  (eq $line.GetCommentSide "previous")}} | ||||
| 																		<div class="ui top attached header"> | ||||
| 																			<span class="ui grey text left"><b>{{$resolveDoer.Name}}</b> {{$.i18n.Tr "repo.issues.review.resolved_by"}}</span> | ||||
| 																			<button id="show-outdated-{{(index $line.Comments 0).ID}}" data-comment="{{(index $line.Comments 0).ID}}" class="ui compact right labeled button show-outdated"> | ||||
| 																				{{svg "octicon-unfold" 16}} | ||||
| 																				{{$.i18n.Tr "repo.issues.review.show_resolved"}} | ||||
| 																			</button> | ||||
| 																			<button id="hide-outdated-{{(index $line.Comments 0).ID}}" data-comment="{{(index $line.Comments 0).ID}}" class="hide ui compact right labeled button hide-outdated"> | ||||
| 																				{{svg "octicon-fold" 16}} | ||||
| 																				{{$.i18n.Tr "repo.issues.review.hide_resolved"}} | ||||
| 																			</button> | ||||
| 																		</div> | ||||
| 																	{{end}} | ||||
| 																	{{if eq $line.GetCommentSide "previous"}} | ||||
| 																		<div class="field comment-code-cloud"> | ||||
| 																		<div id="code-comments-{{(index  $line.Comments 0).ID}}" class="field comment-code-cloud {{if $resolved}}hide{{end}}"> | ||||
| 																			<div class="comment-list"> | ||||
| 																				<ui class="ui comments"> | ||||
| 																				{{ template "repo/diff/comments" dict "root" $ "comments" $line.Comments}} | ||||
| 																				</ui> | ||||
| 																			</div> | ||||
| 																		{{template "repo/diff/comment_form_datahandler" dict "reply" (index $line.Comments 0).ReviewID "hidden" true "root" $ "comment" (index $line.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 $line.Comments 0).ID}}" data-update-url="{{$.RepoLink}}/issues/resolve_conversation" > | ||||
| 																					{{if $resolved}} | ||||
| 																						{{$.i18n.Tr "repo.issues.review.un_resolve_conversation"}} | ||||
| 																					{{else}} | ||||
| 																						{{$.i18n.Tr "repo.issues.review.resolve_conversation"}} | ||||
| 																					{{end}} | ||||
| 																				</button> | ||||
| 																			{{end}} | ||||
| 																		</div> | ||||
| 																	{{end}} | ||||
| 																</td> | ||||
| 																<td class="lines-num"></td> | ||||
| 																<td class="lines-type-marker"></td> | ||||
| 																<td class="add-comment-right"> | ||||
| 																	{{if and $resolved (eq $line.GetCommentSide "proposed")}} | ||||
| 																		<div class="ui top attached header"> | ||||
| 																			<span class="ui grey text left"><b>{{$resolveDoer.Name}}</b> {{$.i18n.Tr "repo.issues.review.resolved_by"}}</span>	 | ||||
| 																			<button id="show-outdated-{{(index $line.Comments 0).ID}}" data-comment="{{(index $line.Comments 0).ID}}" class="ui compact right labeled button show-outdated"> | ||||
| 																				{{svg "octicon-unfold" 16}} | ||||
| 																				{{$.i18n.Tr "repo.issues.review.show_resolved"}} | ||||
| 																			</button> | ||||
| 																			<button id="hide-outdated-{{(index $line.Comments 0).ID}}" data-comment="{{(index $line.Comments 0).ID}}" class="hide ui compact right labeled button hide-outdated"> | ||||
| 																				{{svg "octicon-fold" 16}} | ||||
| 																				{{$.i18n.Tr "repo.issues.review.hide_resolved"}} | ||||
| 																			</button>	 | ||||
| 																		</div> | ||||
| 																	{{end}} | ||||
| 																	{{if eq $line.GetCommentSide "proposed"}} | ||||
| 																		<div class="field comment-code-cloud"> | ||||
| 																		<div id="code-comments-{{(index  $line.Comments 0).ID}}" class="field comment-code-cloud {{if $resolved}}hide{{end}}"> | ||||
| 																			<div class="comment-list"> | ||||
| 																				<ui class="ui comments"> | ||||
| 																				{{ template "repo/diff/comments" dict "root" $ "comments" $line.Comments}} | ||||
| 																				</ui> | ||||
| 																			</div> | ||||
| 																			{{template "repo/diff/comment_form_datahandler" dict "reply" (index $line.Comments 0).ReviewID "hidden" true "root" $ "comment" (index $line.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 $line.Comments 0).ID}}" data-update-url="{{$.RepoLink}}/issues/resolve_conversation" > | ||||
| 																					{{if $resolved}} | ||||
| 																						{{$.i18n.Tr "repo.issues.review.un_resolve_conversation"}} | ||||
| 																					{{else}} | ||||
| 																						{{$.i18n.Tr "repo.issues.review.resolve_conversation"}} | ||||
| 																					{{end}} | ||||
| 																				</button> | ||||
| 																			{{end}} | ||||
| 																		</div> | ||||
| 																	{{end}} | ||||
| 																</td> | ||||
|  |  | |||
|  | @ -23,17 +23,42 @@ | |||
| 			<td class="lines-code{{if (not $line.RightIdx)}} lines-code-old{{end}}">{{if and $.root.SignedUserID $line.CanComment $.root.PageIsPullFiles}}<a class="ui green 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}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{$section.GetComputedInlineDiffFor $line}}</span></td> | ||||
| 		</tr> | ||||
| 		{{if gt (len $line.Comments) 0}} | ||||
| 			{{$resolved := (index $line.Comments 0).IsResolved}} | ||||
| 			{{$resolveDoer := (index $line.Comments 0).ResolveDoer}} | ||||
| 			{{$isNotPending := (not (eq (index $line.Comments 0).Review.Type 0))}} | ||||
| 		<tr> | ||||
| 			<td colspan="2" class="lines-num"></td> | ||||
| 			<td class="lines-type-marker"></td> | ||||
| 			<td class="add-comment-left add-comment-right"> | ||||
| 				<div class="field comment-code-cloud"> | ||||
| 				{{if $resolved}} | ||||
| 					<div class = "ui attached header"> | ||||
| 						<span class="ui grey text left"><b>{{$resolveDoer.Name}}</b> {{$.root.i18n.Tr "repo.issues.review.resolved_by"}}</span> | ||||
| 						<button id="show-outdated-{{(index $line.Comments 0).ID}}" data-comment="{{(index $line.Comments 0).ID}}" class="ui compact right labeled button show-outdated"> | ||||
| 							{{svg "octicon-unfold" 16}} | ||||
| 								{{$.root.i18n.Tr "repo.issues.review.show_resolved"}} | ||||
| 						</button> | ||||
| 						<button id="hide-outdated-{{(index $line.Comments 0).ID}}" data-comment="{{(index $line.Comments 0).ID}}" class="hide ui compact right labeled button hide-outdated"> | ||||
| 							{{svg "octicon-fold" 16}} | ||||
| 							{{$.root.i18n.Tr "repo.issues.review.hide_resolved"}} | ||||
| 						</button> | ||||
| 					</div> | ||||
| 				{{end}} | ||||
| 				<div id="code-comments-{{(index  $line.Comments 0).ID}}" class="field comment-code-cloud {{if $resolved}}hide{{end}}"> | ||||
| 					<div class="comment-list"> | ||||
| 						<ui class="ui comments"> | ||||
| 						{{ template "repo/diff/comments" dict "root" $.root "comments" $line.Comments}} | ||||
| 						</ui> | ||||
| 					</div> | ||||
| 					{{template "repo/diff/comment_form_datahandler" dict "hidden" true "reply" (index $line.Comments 0).ReviewID "root" $.root "comment" (index $line.Comments 0)}} | ||||
| 					{{if and $.root.CanMarkConversation $isNotPending}} | ||||
| 						<button class="ui icon tiny button resolve-conversation" data-action="{{if not $resolved}}Resolve{{else}}UnResolve{{end}}" data-comment-id="{{(index $line.Comments 0).ID}}" data-update-url="{{$.root.RepoLink}}/issues/resolve_conversation" > | ||||
| 							{{if $resolved}} | ||||
| 								{{$.root.i18n.Tr "repo.issues.review.un_resolve_conversation"}} | ||||
| 							{{else}} | ||||
| 								{{$.root.i18n.Tr "repo.issues.review.resolve_conversation"}} | ||||
| 							{{end}} | ||||
| 						</button> | ||||
| 					{{end}} | ||||
| 				</div> | ||||
| 			</td> | ||||
| 		</tr> | ||||
|  |  | |||
|  | @ -381,6 +381,7 @@ | |||
| 				</div> | ||||
| 			</div> | ||||
| 			{{end}} | ||||
| 
 | ||||
| 			{{if .Review.CodeComments}} | ||||
| 			<div class="timeline-item event"> | ||||
| 				{{ range $filename, $lines := .Review.CodeComments}} | ||||
|  | @ -388,14 +389,25 @@ | |||
| 							<div class="ui segments"> | ||||
| 								<div class="ui segment"> | ||||
| 									{{$invalid := (index $comms 0).Invalidated}} | ||||
| 								{{if $invalid}} | ||||
| 									{{$resolved := (index $comms 0).IsResolved}} | ||||
| 									{{$resolveDoer := (index $comms 0).ResolveDoer}} | ||||
| 									{{$isNotPending := (not (eq (index $comms 0).Review.Type 0))}} | ||||
| 								{{if or $invalid $resolved}} | ||||
| 									<button id="show-outdated-{{(index $comms 0).ID}}" data-comment="{{(index $comms 0).ID}}" class="ui compact right labeled button show-outdated"> | ||||
| 										{{svg "octicon-fold" 16}} | ||||
| 										{{$.i18n.Tr "repo.issues.review.show_outdated"}} | ||||
| 										{{svg "octicon-unfold" 16}} | ||||
| 										{{if $invalid }} | ||||
| 											{{$.i18n.Tr "repo.issues.review.show_outdated"}} | ||||
| 										{{else}} | ||||
| 											{{$.i18n.Tr "repo.issues.review.show_resolved"}} | ||||
| 										{{end}} | ||||
| 									</button> | ||||
| 									<button id="hide-outdated-{{(index $comms 0).ID}}" data-comment="{{(index $comms 0).ID}}" class="hide ui compact right labeled button hide-outdated"> | ||||
| 										{{svg "octicon-fold" 16}} | ||||
| 										{{$.i18n.Tr "repo.issues.review.hide_outdated"}} | ||||
| 										{{if $invalid}} | ||||
| 											{{$.i18n.Tr "repo.issues.review.hide_outdated"}} | ||||
| 										{{else}} | ||||
| 											{{$.i18n.Tr "repo.issues.review.hide_resolved"}} | ||||
| 										{{end}} | ||||
| 									</button> | ||||
| 								{{end}} | ||||
| 									<a href="{{(index $comms 0).CodeCommentURL}}" class="file-comment">{{$filename}}</a> | ||||
|  | @ -403,7 +415,7 @@ | |||
| 								{{$diff := (CommentMustAsDiff (index $comms 0))}} | ||||
| 								{{if $diff}} | ||||
| 									{{$file := (index $diff.Files 0)}} | ||||
| 									<div id="code-preview-{{(index $comms 0).ID}}" class="ui table segment{{if $invalid}} hide{{end}}"> | ||||
| 									<div id="code-preview-{{(index $comms 0).ID}}" class="ui table segment{{if or $invalid $resolved}} hide{{end}}"> | ||||
| 										<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}}"> | ||||
| 											<div class="file-body file-code code-view code-diff code-diff-unified"> | ||||
| 												<table> | ||||
|  | @ -415,7 +427,7 @@ | |||
| 										</div> | ||||
| 									</div> | ||||
| 								{{end}} | ||||
| 								<div id="code-comments-{{(index $comms 0).ID}}" class="ui segment{{if $invalid}} hide{{end}}"> | ||||
| 								<div id="code-comments-{{(index $comms 0).ID}}" class="ui segment{{if or $invalid $resolved}} hide{{end}}"> | ||||
| 									<div class="ui comments"> | ||||
| 										{{range $comms}} | ||||
| 											{{ $createdSubStr:= TimeSinceUnix .CreatedUnix $.Lang }} | ||||
|  | @ -445,6 +457,20 @@ | |||
| 										{{end}} | ||||
| 									</div> | ||||
| 									{{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" > | ||||
| 											{{if $resolved}} | ||||
| 												{{$.i18n.Tr "repo.issues.review.un_resolve_conversation"}} | ||||
| 											{{else}} | ||||
| 												{{$.i18n.Tr "repo.issues.review.resolve_conversation"}} | ||||
| 											{{end}} | ||||
| 										</button> | ||||
| 									{{end}} | ||||
| 
 | ||||
| 									{{if $resolved}} | ||||
| 										<span class="ui grey text"><b>{{$resolveDoer.Name}}</b> {{$.i18n.Tr "repo.issues.review.resolved_by"}}</span> | ||||
| 									{{end}} | ||||
| 								</div> | ||||
| 							</div> | ||||
| 					{{end}} | ||||
|  |  | |||
|  | @ -2566,6 +2566,19 @@ $(document).ready(async () => { | |||
|     $(e).click(); | ||||
|   }); | ||||
| 
 | ||||
|   $('.resolve-conversation').on('click', function (e) { | ||||
|     e.preventDefault(); | ||||
|     const id = $(this).data('comment-id'); | ||||
|     const action = $(this).data('action'); | ||||
|     const url = $(this).data('update-url'); | ||||
| 
 | ||||
|     $.post(url, { | ||||
|       _csrf: csrf, | ||||
|       action, | ||||
|       comment_id: id, | ||||
|     }).then(reload); | ||||
|   }); | ||||
| 
 | ||||
|   buttonsClickOnEnter(); | ||||
|   searchUsers(); | ||||
|   searchTeams(); | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue