forked from gitea/gitea
Show outdated comments in files changed tab (#24936)
If enabled show a clickable label in the comment. A click on the label opens the Conversation tab with the comment focussed - there you're able to view the old diff (or original diff the comment was created on). **Screenshots** ![image](https://github.com/go-gitea/gitea/assets/1135157/63ab9571-a9ee-4900-9f02-94ab0095f9e7) ![image](https://github.com/go-gitea/gitea/assets/1135157/78f7c225-8d76-46f5-acfd-9b8aab988a6c) When resolved and outdated: ![image](https://github.com/go-gitea/gitea/assets/1135157/6ece9ebd-c792-4aa5-9c35-628694e9d093) Option to enable/disable this (stored in user settings - default is disabled): ![image](https://github.com/go-gitea/gitea/assets/1135157/ed99dfe4-76dc-4c12-bd96-e7e62da50ab5) ![image](https://github.com/go-gitea/gitea/assets/1135157/e837a052-e92e-4a28-906d-9db5bacf93a6) fixes #24913 --------- Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
parent
ce46834b93
commit
25455bc670
|
@ -18,11 +18,11 @@ import (
|
||||||
type CodeComments map[string]map[int64][]*Comment
|
type CodeComments map[string]map[int64][]*Comment
|
||||||
|
|
||||||
// FetchCodeComments will return a 2d-map: ["Path"]["Line"] = Comments at line
|
// FetchCodeComments will return a 2d-map: ["Path"]["Line"] = Comments at line
|
||||||
func FetchCodeComments(ctx context.Context, issue *Issue, currentUser *user_model.User) (CodeComments, error) {
|
func FetchCodeComments(ctx context.Context, issue *Issue, currentUser *user_model.User, showOutdatedComments bool) (CodeComments, error) {
|
||||||
return fetchCodeCommentsByReview(ctx, issue, currentUser, nil)
|
return fetchCodeCommentsByReview(ctx, issue, currentUser, nil, showOutdatedComments)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchCodeCommentsByReview(ctx context.Context, issue *Issue, currentUser *user_model.User, review *Review) (CodeComments, error) {
|
func fetchCodeCommentsByReview(ctx context.Context, issue *Issue, currentUser *user_model.User, review *Review, showOutdatedComments bool) (CodeComments, error) {
|
||||||
pathToLineToComment := make(CodeComments)
|
pathToLineToComment := make(CodeComments)
|
||||||
if review == nil {
|
if review == nil {
|
||||||
review = &Review{ID: 0}
|
review = &Review{ID: 0}
|
||||||
|
@ -33,7 +33,7 @@ func fetchCodeCommentsByReview(ctx context.Context, issue *Issue, currentUser *u
|
||||||
ReviewID: review.ID,
|
ReviewID: review.ID,
|
||||||
}
|
}
|
||||||
|
|
||||||
comments, err := findCodeComments(ctx, opts, issue, currentUser, review)
|
comments, err := findCodeComments(ctx, opts, issue, currentUser, review, showOutdatedComments)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -47,15 +47,17 @@ func fetchCodeCommentsByReview(ctx context.Context, issue *Issue, currentUser *u
|
||||||
return pathToLineToComment, nil
|
return pathToLineToComment, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func findCodeComments(ctx context.Context, opts FindCommentsOptions, issue *Issue, currentUser *user_model.User, review *Review) ([]*Comment, error) {
|
func findCodeComments(ctx context.Context, opts FindCommentsOptions, issue *Issue, currentUser *user_model.User, review *Review, showOutdatedComments bool) ([]*Comment, error) {
|
||||||
var comments CommentList
|
var comments CommentList
|
||||||
if review == nil {
|
if review == nil {
|
||||||
review = &Review{ID: 0}
|
review = &Review{ID: 0}
|
||||||
}
|
}
|
||||||
conds := opts.ToConds()
|
conds := opts.ToConds()
|
||||||
if review.ID == 0 {
|
|
||||||
|
if !showOutdatedComments && review.ID == 0 {
|
||||||
conds = conds.And(builder.Eq{"invalidated": false})
|
conds = conds.And(builder.Eq{"invalidated": false})
|
||||||
}
|
}
|
||||||
|
|
||||||
e := db.GetEngine(ctx)
|
e := db.GetEngine(ctx)
|
||||||
if err := e.Where(conds).
|
if err := e.Where(conds).
|
||||||
Asc("comment.created_unix").
|
Asc("comment.created_unix").
|
||||||
|
@ -118,12 +120,12 @@ func findCodeComments(ctx context.Context, opts FindCommentsOptions, issue *Issu
|
||||||
}
|
}
|
||||||
|
|
||||||
// FetchCodeCommentsByLine fetches the code comments for a given treePath and line number
|
// FetchCodeCommentsByLine fetches the code comments for a given treePath and line number
|
||||||
func FetchCodeCommentsByLine(ctx context.Context, issue *Issue, currentUser *user_model.User, treePath string, line int64) ([]*Comment, error) {
|
func FetchCodeCommentsByLine(ctx context.Context, issue *Issue, currentUser *user_model.User, treePath string, line int64, showOutdatedComments bool) ([]*Comment, error) {
|
||||||
opts := FindCommentsOptions{
|
opts := FindCommentsOptions{
|
||||||
Type: CommentTypeCode,
|
Type: CommentTypeCode,
|
||||||
IssueID: issue.ID,
|
IssueID: issue.ID,
|
||||||
TreePath: treePath,
|
TreePath: treePath,
|
||||||
Line: line,
|
Line: line,
|
||||||
}
|
}
|
||||||
return findCodeComments(ctx, opts, issue, currentUser, nil)
|
return findCodeComments(ctx, opts, issue, currentUser, nil, showOutdatedComments)
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ func TestFetchCodeComments(t *testing.T) {
|
||||||
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||||
res, err := issues_model.FetchCodeComments(db.DefaultContext, issue, user)
|
res, err := issues_model.FetchCodeComments(db.DefaultContext, issue, user, false)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, res, "README.md")
|
assert.Contains(t, res, "README.md")
|
||||||
assert.Contains(t, res["README.md"], int64(4))
|
assert.Contains(t, res["README.md"], int64(4))
|
||||||
|
@ -58,7 +58,7 @@ func TestFetchCodeComments(t *testing.T) {
|
||||||
assert.Equal(t, int64(4), res["README.md"][4][0].ID)
|
assert.Equal(t, int64(4), res["README.md"][4][0].ID)
|
||||||
|
|
||||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
res, err = issues_model.FetchCodeComments(db.DefaultContext, issue, user2)
|
res, err = issues_model.FetchCodeComments(db.DefaultContext, issue, user2, false)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, res, 1)
|
assert.Len(t, res, 1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,7 +141,7 @@ func (r *Review) LoadCodeComments(ctx context.Context) (err error) {
|
||||||
if err = r.loadIssue(ctx); err != nil {
|
if err = r.loadIssue(ctx); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.CodeComments, err = fetchCodeCommentsByReview(ctx, r.Issue, nil, r)
|
r.CodeComments, err = fetchCodeCommentsByReview(ctx, r.Issue, nil, r, false)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ const (
|
||||||
SettingsKeyHiddenCommentTypes = "issue.hidden_comment_types"
|
SettingsKeyHiddenCommentTypes = "issue.hidden_comment_types"
|
||||||
// SettingsKeyDiffWhitespaceBehavior is the setting key for whitespace behavior of diff
|
// SettingsKeyDiffWhitespaceBehavior is the setting key for whitespace behavior of diff
|
||||||
SettingsKeyDiffWhitespaceBehavior = "diff.whitespace_behaviour"
|
SettingsKeyDiffWhitespaceBehavior = "diff.whitespace_behaviour"
|
||||||
|
// SettingsKeyShowOutdatedComments is the setting key wether or not to show outdated comments in PRs
|
||||||
|
SettingsKeyShowOutdatedComments = "comment_code.show_outdated"
|
||||||
// UserActivityPubPrivPem is user's private key
|
// UserActivityPubPrivPem is user's private key
|
||||||
UserActivityPubPrivPem = "activitypub.priv_pem"
|
UserActivityPubPrivPem = "activitypub.priv_pem"
|
||||||
// UserActivityPubPubPem is user's public key
|
// UserActivityPubPubPem is user's public key
|
||||||
|
|
|
@ -1611,6 +1611,9 @@ issues.review.pending.tooltip = This comment is not currently visible to other u
|
||||||
issues.review.review = Review
|
issues.review.review = Review
|
||||||
issues.review.reviewers = Reviewers
|
issues.review.reviewers = Reviewers
|
||||||
issues.review.outdated = Outdated
|
issues.review.outdated = Outdated
|
||||||
|
issues.review.outdated_description = Content has changed since this comment was made
|
||||||
|
issues.review.option.show_outdated_comments = Show outdated comments
|
||||||
|
issues.review.option.hide_outdated_comments = Hide outdated comments
|
||||||
issues.review.show_outdated = Show outdated
|
issues.review.show_outdated = Show outdated
|
||||||
issues.review.hide_outdated = Hide outdated
|
issues.review.hide_outdated = Hide outdated
|
||||||
issues.review.show_resolved = Show resolved
|
issues.review.show_resolved = Show resolved
|
||||||
|
|
|
@ -5,6 +5,7 @@ package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
system_model "code.gitea.io/gitea/models/system"
|
system_model "code.gitea.io/gitea/models/system"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -88,3 +89,27 @@ func SetWhitespaceBehavior(ctx *context.Context) {
|
||||||
ctx.Data["WhitespaceBehavior"] = whitespaceBehavior
|
ctx.Data["WhitespaceBehavior"] = whitespaceBehavior
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetShowOutdatedComments set the show outdated comments option as context variable
|
||||||
|
func SetShowOutdatedComments(ctx *context.Context) {
|
||||||
|
showOutdatedCommentsValue := ctx.FormString("show-outdated")
|
||||||
|
// var showOutdatedCommentsValue string
|
||||||
|
|
||||||
|
if showOutdatedCommentsValue != "true" && showOutdatedCommentsValue != "false" {
|
||||||
|
// invalid or no value for this form string -> use default or stored user setting
|
||||||
|
if ctx.IsSigned {
|
||||||
|
showOutdatedCommentsValue, _ = user_model.GetUserSetting(ctx.Doer.ID, user_model.SettingsKeyShowOutdatedComments, "false")
|
||||||
|
} else {
|
||||||
|
// not logged in user -> use the default value
|
||||||
|
showOutdatedCommentsValue = "false"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// valid value -> update user setting if user is logged in
|
||||||
|
if ctx.IsSigned {
|
||||||
|
_ = user_model.SetUserSetting(ctx.Doer.ID, user_model.SettingsKeyShowOutdatedComments, showOutdatedCommentsValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showOutdatedComments, _ := strconv.ParseBool(showOutdatedCommentsValue)
|
||||||
|
ctx.Data["ShowOutdatedComments"] = showOutdatedComments
|
||||||
|
}
|
||||||
|
|
|
@ -761,7 +761,7 @@ func ViewPullFiles(ctx *context.Context) {
|
||||||
"numberOfViewedFiles": diff.NumViewedFiles,
|
"numberOfViewedFiles": diff.NumViewedFiles,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = diff.LoadComments(ctx, issue, ctx.Doer); err != nil {
|
if err = diff.LoadComments(ctx, issue, ctx.Doer, ctx.Data["ShowOutdatedComments"].(bool)); err != nil {
|
||||||
ctx.ServerError("LoadComments", err)
|
ctx.ServerError("LoadComments", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,7 +159,7 @@ func UpdateResolveConversation(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderConversation(ctx *context.Context, comment *issues_model.Comment) {
|
func renderConversation(ctx *context.Context, comment *issues_model.Comment) {
|
||||||
comments, err := issues_model.FetchCodeCommentsByLine(ctx, comment.Issue, ctx.Doer, comment.TreePath, comment.Line)
|
comments, err := issues_model.FetchCodeCommentsByLine(ctx, comment.Issue, ctx.Doer, comment.TreePath, comment.Line, ctx.Data["ShowOutdatedComments"].(bool))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("FetchCodeCommentsByLine", err)
|
ctx.ServerError("FetchCodeCommentsByLine", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -1037,7 +1037,7 @@ func registerRoutes(m *web.Route) {
|
||||||
m.Post("/dismiss_review", reqRepoAdmin, web.Bind(forms.DismissReviewForm{}), repo.DismissReview)
|
m.Post("/dismiss_review", reqRepoAdmin, web.Bind(forms.DismissReviewForm{}), repo.DismissReview)
|
||||||
m.Post("/status", reqRepoIssuesOrPullsWriter, repo.UpdateIssueStatus)
|
m.Post("/status", reqRepoIssuesOrPullsWriter, repo.UpdateIssueStatus)
|
||||||
m.Post("/delete", reqRepoAdmin, repo.BatchDeleteIssues)
|
m.Post("/delete", reqRepoAdmin, repo.BatchDeleteIssues)
|
||||||
m.Post("/resolve_conversation", reqRepoIssuesOrPullsReader, repo.UpdateResolveConversation)
|
m.Post("/resolve_conversation", reqRepoIssuesOrPullsReader, repo.SetShowOutdatedComments, repo.UpdateResolveConversation)
|
||||||
m.Post("/attachments", repo.UploadIssueAttachment)
|
m.Post("/attachments", repo.UploadIssueAttachment)
|
||||||
m.Post("/attachments/remove", repo.DeleteAttachment)
|
m.Post("/attachments/remove", repo.DeleteAttachment)
|
||||||
m.Delete("/unpin/{index}", reqRepoAdmin, repo.IssueUnpin)
|
m.Delete("/unpin/{index}", reqRepoAdmin, repo.IssueUnpin)
|
||||||
|
@ -1285,10 +1285,10 @@ func registerRoutes(m *web.Route) {
|
||||||
m.Post("/set_allow_maintainer_edit", web.Bind(forms.UpdateAllowEditsForm{}), repo.SetAllowEdits)
|
m.Post("/set_allow_maintainer_edit", web.Bind(forms.UpdateAllowEditsForm{}), repo.SetAllowEdits)
|
||||||
m.Post("/cleanup", context.RepoMustNotBeArchived(), context.RepoRef(), repo.CleanUpPullRequest)
|
m.Post("/cleanup", context.RepoMustNotBeArchived(), context.RepoRef(), repo.CleanUpPullRequest)
|
||||||
m.Group("/files", func() {
|
m.Group("/files", func() {
|
||||||
m.Get("", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.ViewPullFiles)
|
m.Get("", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFiles)
|
||||||
m.Group("/reviews", func() {
|
m.Group("/reviews", func() {
|
||||||
m.Get("/new_comment", repo.RenderNewCodeCommentForm)
|
m.Get("/new_comment", repo.RenderNewCodeCommentForm)
|
||||||
m.Post("/comments", web.Bind(forms.CodeCommentForm{}), repo.CreateCodeComment)
|
m.Post("/comments", web.Bind(forms.CodeCommentForm{}), repo.SetShowOutdatedComments, repo.CreateCodeComment)
|
||||||
m.Post("/submit", web.Bind(forms.SubmitReviewForm{}), repo.SubmitReview)
|
m.Post("/submit", web.Bind(forms.SubmitReviewForm{}), repo.SubmitReview)
|
||||||
}, context.RepoMustNotBeArchived())
|
}, context.RepoMustNotBeArchived())
|
||||||
})
|
})
|
||||||
|
|
|
@ -450,8 +450,8 @@ type Diff struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadComments loads comments into each line
|
// LoadComments loads comments into each line
|
||||||
func (diff *Diff) LoadComments(ctx context.Context, issue *issues_model.Issue, currentUser *user_model.User) error {
|
func (diff *Diff) LoadComments(ctx context.Context, issue *issues_model.Issue, currentUser *user_model.User, showOutdatedComments bool) error {
|
||||||
allComments, err := issues_model.FetchCodeComments(ctx, issue, currentUser)
|
allComments, err := issues_model.FetchCodeComments(ctx, issue, currentUser, showOutdatedComments)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -594,16 +594,26 @@ func setupDefaultDiff() *Diff {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDiff_LoadComments(t *testing.T) {
|
func TestDiff_LoadCommentsNoOutdated(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||||
diff := setupDefaultDiff()
|
diff := setupDefaultDiff()
|
||||||
assert.NoError(t, diff.LoadComments(db.DefaultContext, issue, user))
|
assert.NoError(t, diff.LoadComments(db.DefaultContext, issue, user, false))
|
||||||
assert.Len(t, diff.Files[0].Sections[0].Lines[0].Comments, 2)
|
assert.Len(t, diff.Files[0].Sections[0].Lines[0].Comments, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDiff_LoadCommentsWithOutdated(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
|
||||||
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||||
|
diff := setupDefaultDiff()
|
||||||
|
assert.NoError(t, diff.LoadComments(db.DefaultContext, issue, user, true))
|
||||||
|
assert.Len(t, diff.Files[0].Sections[0].Lines[0].Comments, 3)
|
||||||
|
}
|
||||||
|
|
||||||
func TestDiffLine_CanComment(t *testing.T) {
|
func TestDiffLine_CanComment(t *testing.T) {
|
||||||
assert.False(t, (&DiffLine{Type: DiffLineSection}).CanComment())
|
assert.False(t, (&DiffLine{Type: DiffLineSection}).CanComment())
|
||||||
assert.False(t, (&DiffLine{Type: DiffLineAdd, Comments: []*issues_model.Comment{{Content: "bla"}}}).CanComment())
|
assert.False(t, (&DiffLine{Type: DiffLineAdd, Comments: []*issues_model.Comment{{Content: "bla"}}}).CanComment())
|
||||||
|
|
|
@ -31,6 +31,12 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="comment-header-right actions gt-df gt-ac">
|
<div class="comment-header-right actions gt-df gt-ac">
|
||||||
|
{{if .Invalidated}}
|
||||||
|
{{$referenceUrl := printf "%s#%s" $.root.Issue.Link .HashTag}}
|
||||||
|
<a href="{{AppSubUrl}}{{$referenceUrl}}" class="ui label basic small" data-tooltip-content="{{$.root.locale.Tr "repo.issues.review.outdated_description"}}">
|
||||||
|
{{$.root.locale.Tr "repo.issues.review.outdated"}}
|
||||||
|
</a>
|
||||||
|
{{end}}
|
||||||
{{if and .Review}}
|
{{if and .Review}}
|
||||||
{{if eq .Review.Type 0}}
|
{{if eq .Review.Type 0}}
|
||||||
<div class="ui label basic small yellow pending-label" data-tooltip-content="{{$.root.locale.Tr "repo.issues.review.pending.tooltip" ($.root.locale.Tr "repo.diff.review") ($.root.locale.Tr "repo.diff.review.approve") ($.root.locale.Tr "repo.diff.review.comment") ($.root.locale.Tr "repo.diff.review.reject")}}">
|
<div class="ui label basic small yellow pending-label" data-tooltip-content="{{$.root.locale.Tr "repo.issues.review.pending.tooltip" ($.root.locale.Tr "repo.diff.review") ($.root.locale.Tr "repo.diff.review.approve") ($.root.locale.Tr "repo.diff.review.comment") ($.root.locale.Tr "repo.diff.review.reject")}}">
|
||||||
|
|
|
@ -1,14 +1,25 @@
|
||||||
{{$resolved := (index .comments 0).IsResolved}}
|
{{$resolved := (index .comments 0).IsResolved}}
|
||||||
|
{{$invalid := (index .comments 0).Invalidated}}
|
||||||
{{$resolveDoer := (index .comments 0).ResolveDoer}}
|
{{$resolveDoer := (index .comments 0).ResolveDoer}}
|
||||||
{{$isNotPending := (not (eq (index .comments 0).Review.Type 0))}}
|
{{$isNotPending := (not (eq (index .comments 0).Review.Type 0))}}
|
||||||
|
{{$referenceUrl := printf "%s#%s" $.Issue.Link (index .comments 0).HashTag}}
|
||||||
<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}}">
|
<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}}
|
{{if $resolved}}
|
||||||
<div class="ui attached header resolved-placeholder gt-df gt-ac gt-sb">
|
<div class="ui attached header resolved-placeholder gt-df gt-ac gt-sb">
|
||||||
<div class="ui grey text">
|
<div class="ui grey text gt-df gt-ac gt-fw gt-gap-2">
|
||||||
{{svg "octicon-check" 16 "icon gt-mr-2"}}
|
{{svg "octicon-check" 16 "icon gt-mr-2"}}
|
||||||
<b>{{$resolveDoer.Name}}</b> {{$.locale.Tr "repo.issues.review.resolved_by"}}
|
<b>{{$resolveDoer.Name}}</b> {{$.locale.Tr "repo.issues.review.resolved_by"}}
|
||||||
|
{{if $invalid}}
|
||||||
|
<!--
|
||||||
|
We only handle the case $resolved=true and $invalid=true in this template because if the comment is not resolved it has the outdated label in the comments area (not the header above).
|
||||||
|
The case $resolved=false and $invalid=true is handled in repo/diff/comments.tmpl
|
||||||
|
-->
|
||||||
|
<a href="{{AppSubUrl}}{{$referenceUrl}}" class="ui label basic small gt-ml-3" data-tooltip-content="{{$.locale.Tr "repo.issues.review.outdated_description"}}">
|
||||||
|
{{$.locale.Tr "repo.issues.review.outdated"}}
|
||||||
|
</a>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="gt-df gt-ac gt-gap-3">
|
||||||
<button id="show-outdated-{{(index .comments 0).ID}}" data-comment="{{(index .comments 0).ID}}" class="ui tiny labeled button show-outdated gt-df gt-ac">
|
<button id="show-outdated-{{(index .comments 0).ID}}" data-comment="{{(index .comments 0).ID}}" class="ui tiny labeled button show-outdated gt-df gt-ac">
|
||||||
{{svg "octicon-unfold" 16 "gt-mr-3"}}
|
{{svg "octicon-unfold" 16 "gt-mr-3"}}
|
||||||
{{$.locale.Tr "repo.issues.review.show_resolved"}}
|
{{$.locale.Tr "repo.issues.review.show_resolved"}}
|
||||||
|
|
|
@ -14,5 +14,20 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
<a id="expand-files-btn" class="item">{{.locale.Tr "repo.pulls.expand_files"}}</a>
|
<a id="expand-files-btn" class="item">{{.locale.Tr "repo.pulls.expand_files"}}</a>
|
||||||
<a id="collapse-files-btn"class="item">{{.locale.Tr "repo.pulls.collapse_files"}}</a>
|
<a id="collapse-files-btn"class="item">{{.locale.Tr "repo.pulls.collapse_files"}}</a>
|
||||||
|
{{if .Issue.Index}}
|
||||||
|
{{if .ShowOutdatedComments}}
|
||||||
|
<a class="item" href="?style={{if $.IsSplitStyle}}split{{else}}unified{{end}}&whitespace={{$.WhitespaceBehavior}}&show-outdated=false">
|
||||||
|
<label class="gt-pointer-events-none">
|
||||||
|
{{.locale.Tr "repo.issues.review.option.hide_outdated_comments"}}
|
||||||
|
</label>
|
||||||
|
</a>
|
||||||
|
{{else}}
|
||||||
|
<a class="item" href="?style={{if $.IsSplitStyle}}split{{else}}unified{{end}}&whitespace={{$.WhitespaceBehavior}}&show-outdated=true">
|
||||||
|
<label class="gt-pointer-events-none">
|
||||||
|
{{.locale.Tr "repo.issues.review.option.show_outdated_comments"}}
|
||||||
|
</label>
|
||||||
|
</a>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
<div class="ui dropdown tiny basic button" data-tooltip-content="{{.locale.Tr "repo.diff.whitespace_button"}}">
|
<div class="ui dropdown tiny basic button" data-tooltip-content="{{.locale.Tr "repo.diff.whitespace_button"}}">
|
||||||
{{svg "gitea-whitespace"}}
|
{{svg "gitea-whitespace"}}
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="item" href="?style={{if .IsSplitStyle}}split{{else}}unified{{end}}&whitespace=show-all">
|
<a class="item" href="?style={{if .IsSplitStyle}}split{{else}}unified{{end}}&whitespace=show-all&show-outdated={{$.ShowOutdatedComments}}">
|
||||||
<label class="gt-pointer-events-none">
|
<label class="gt-pointer-events-none">
|
||||||
<input class="gt-mr-3 gt-pointer-events-none" type="radio"{{if eq .WhitespaceBehavior "show-all"}} checked{{end}}>
|
<input class="gt-mr-3 gt-pointer-events-none" type="radio"{{if eq .WhitespaceBehavior "show-all"}} checked{{end}}>
|
||||||
{{.locale.Tr "repo.diff.whitespace_show_everything"}}
|
{{.locale.Tr "repo.diff.whitespace_show_everything"}}
|
||||||
</label>
|
</label>
|
||||||
</a>
|
</a>
|
||||||
<a class="item" href="?style={{if .IsSplitStyle}}split{{else}}unified{{end}}&whitespace=ignore-all">
|
<a class="item" href="?style={{if .IsSplitStyle}}split{{else}}unified{{end}}&whitespace=ignore-all&show-outdated={{$.ShowOutdatedComments}}">
|
||||||
<label class="gt-pointer-events-none">
|
<label class="gt-pointer-events-none">
|
||||||
<input class="gt-mr-3 gt-pointer-events-none" type="radio"{{if eq .WhitespaceBehavior "ignore-all"}} checked{{end}}>
|
<input class="gt-mr-3 gt-pointer-events-none" type="radio"{{if eq .WhitespaceBehavior "ignore-all"}} checked{{end}}>
|
||||||
{{.locale.Tr "repo.diff.whitespace_ignore_all_whitespace"}}
|
{{.locale.Tr "repo.diff.whitespace_ignore_all_whitespace"}}
|
||||||
</label>
|
</label>
|
||||||
</a>
|
</a>
|
||||||
<a class="item" href="?style={{if .IsSplitStyle}}split{{else}}unified{{end}}&whitespace=ignore-change">
|
<a class="item" href="?style={{if .IsSplitStyle}}split{{else}}unified{{end}}&whitespace=ignore-change&show-outdated={{$.ShowOutdatedComments}}">
|
||||||
<label class="gt-pointer-events-none">
|
<label class="gt-pointer-events-none">
|
||||||
<input class="gt-mr-3 gt-pointer-events-none" type="radio"{{if eq .WhitespaceBehavior "ignore-change"}} checked{{end}}>
|
<input class="gt-mr-3 gt-pointer-events-none" type="radio"{{if eq .WhitespaceBehavior "ignore-change"}} checked{{end}}>
|
||||||
{{.locale.Tr "repo.diff.whitespace_ignore_amount_changes"}}
|
{{.locale.Tr "repo.diff.whitespace_ignore_amount_changes"}}
|
||||||
</label>
|
</label>
|
||||||
</a>
|
</a>
|
||||||
<a class="item" href="?style={{if .IsSplitStyle}}split{{else}}unified{{end}}&whitespace=ignore-eol">
|
<a class="item" href="?style={{if .IsSplitStyle}}split{{else}}unified{{end}}&whitespace=ignore-eol&show-outdated={{$.ShowOutdatedComments}}">
|
||||||
<label class="gt-pointer-events-none">
|
<label class="gt-pointer-events-none">
|
||||||
<input class="gt-mr-3 gt-pointer-events-none" type="radio"{{if eq .WhitespaceBehavior "ignore-eol"}} checked{{end}}>
|
<input class="gt-mr-3 gt-pointer-events-none" type="radio"{{if eq .WhitespaceBehavior "ignore-eol"}} checked{{end}}>
|
||||||
{{.locale.Tr "repo.diff.whitespace_ignore_at_eol"}}
|
{{.locale.Tr "repo.diff.whitespace_ignore_at_eol"}}
|
||||||
|
@ -27,4 +27,4 @@
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a class="ui tiny basic button" href="?style={{if .IsSplitStyle}}unified{{else}}split{{end}}&whitespace={{$.WhitespaceBehavior}}" data-tooltip-content="{{if .IsSplitStyle}}{{.locale.Tr "repo.diff.show_unified_view"}}{{else}}{{.locale.Tr "repo.diff.show_split_view"}}{{end}}">{{if .IsSplitStyle}}{{svg "gitea-join"}}{{else}}{{svg "gitea-split"}}{{end}}</a>
|
<a class="ui tiny basic button" href="?style={{if .IsSplitStyle}}unified{{else}}split{{end}}&whitespace={{$.WhitespaceBehavior}}&show-outdated={{$.ShowOutdatedComments}}" data-tooltip-content="{{if .IsSplitStyle}}{{.locale.Tr "repo.diff.show_unified_view"}}{{else}}{{.locale.Tr "repo.diff.show_split_view"}}{{end}}">{{if .IsSplitStyle}}{{svg "gitea-join"}}{{else}}{{svg "gitea-split"}}{{end}}</a>
|
||||||
|
|
|
@ -488,7 +488,7 @@
|
||||||
<div class="gt-df gt-ac">
|
<div class="gt-df gt-ac">
|
||||||
<a href="{{(index $comms 0).CodeCommentLink}}" class="file-comment gt-ml-3 gt-word-break">{{$filename}}</a>
|
<a href="{{(index $comms 0).CodeCommentLink}}" class="file-comment gt-ml-3 gt-word-break">{{$filename}}</a>
|
||||||
{{if $invalid}}
|
{{if $invalid}}
|
||||||
<span class="ui label basic small gt-ml-3">
|
<span class="ui label basic small gt-ml-3" data-tooltip-content="{{$.locale.Tr "repo.issues.review.outdated_description"}}">
|
||||||
{{$.locale.Tr "repo.issues.review.outdated"}}
|
{{$.locale.Tr "repo.issues.review.outdated"}}
|
||||||
</span>
|
</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -1702,6 +1702,10 @@
|
||||||
.repository .diff-box .resolved-placeholder {
|
.repository .diff-box .resolved-placeholder {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
font-size: 14px !important;
|
||||||
|
height: 36px;
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.repository .diff-box .resolved-placeholder .button {
|
.repository .diff-box .resolved-placeholder .button {
|
||||||
|
@ -1728,10 +1732,6 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.repository .diff-file-box .code-diff {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.repository .diff-file-box .code-diff td {
|
.repository .diff-file-box .code-diff td {
|
||||||
padding: 0 0 0 10px !important;
|
padding: 0 0 0 10px !important;
|
||||||
border-top: 0;
|
border-top: 0;
|
||||||
|
@ -2495,14 +2495,17 @@
|
||||||
left: 7px;
|
left: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-header .actions a {
|
.comment-header .actions a:not(.label) {
|
||||||
margin-right: 0 !important;
|
|
||||||
padding: 0.5rem !important;
|
padding: 0.5rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-header-left > * + *,
|
.comment-header .actions .label {
|
||||||
.comment-header-right > * + * {
|
margin: 0 !important;
|
||||||
margin-left: 0.25rem;
|
}
|
||||||
|
|
||||||
|
.comment-header-left,
|
||||||
|
.comment-header-right {
|
||||||
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-body {
|
.comment-body {
|
||||||
|
|
|
@ -128,7 +128,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-code-cloud .attached.header {
|
.comment-code-cloud .attached.header {
|
||||||
padding: 0.1rem 1rem;
|
padding: 1px 8px 1px 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-code-cloud .attached.header .text {
|
.comment-code-cloud .attached.header .text {
|
||||||
|
|
Loading…
Reference in New Issue