diff --git a/modelmigration/migrations.go b/modelmigration/migrations.go index c160e7f1938..f1e0fc25bed 100644 --- a/modelmigration/migrations.go +++ b/modelmigration/migrations.go @@ -437,6 +437,7 @@ func prepareMigrationTasks() []*migration { newMigration(358, "Track previous remember-me token hashes", v29.AddPreviousAuthTokenHash), newMigration(359, "Add stage and number columns to action_task_step", v29.AddStageAndNumberToActionTaskStep), newMigration(360, "Move branch protection settings to JSON", v29.MoveBranchProtectionConfigToJSON), + newMigration(361, "Drop legacy commit_id column from comment", v29.DropCommentCommitID), } return preparedMigrations } diff --git a/modelmigration/v29/v361.go b/modelmigration/v29/v361.go new file mode 100644 index 00000000000..985efce0b0c --- /dev/null +++ b/modelmigration/v29/v361.go @@ -0,0 +1,21 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v29 + +import ( + "context" + + "gitea.dev/modelmigration/base" +) + +func DropCommentCommitID(ctx context.Context, x base.EngineMigration) error { + exists, err := x.Dialect().IsColumnExist(x.DB(), ctx, "comment", "commit_id") + if err != nil || !exists { + return err + } + + return base.EngineTransaction(x, func(sess base.Session) error { + return base.DropTableColumns(sess, "comment", "commit_id") + }) +} diff --git a/modules/templates/util_dict.go b/modules/templates/util_dict.go index 09dc838d6bf..127e906ef52 100644 --- a/modules/templates/util_dict.go +++ b/modules/templates/util_dict.go @@ -15,23 +15,7 @@ import ( "gitea.dev/modules/setting" ) -func dictMerge(base map[string]any, arg any) bool { - if arg == nil { - return true - } - rv := reflect.ValueOf(arg) - if rv.Kind() == reflect.Map { - for _, k := range rv.MapKeys() { - base[k.String()] = rv.MapIndex(k).Interface() - } - return true - } - return false -} - // dict is a helper function for creating a map[string]any from a list of key-value pairs. -// If the key is dot ".", the value is merged into the base map, just like Golang template's dot syntax: dot means current -// The dot syntax is highly discouraged because it might cause unclear key conflicts. It's always good to use explicit keys. func dict(args ...any) (map[string]any, error) { if len(args)%2 != 0 { return nil, errors.New("invalid dict constructor syntax: must have key-value pairs") @@ -42,13 +26,7 @@ func dict(args ...any) (map[string]any, error) { if !ok { return nil, fmt.Errorf("invalid dict constructor syntax: unable to merge args[%d]", i) } - if key == "." { - if ok = dictMerge(m, args[i+1]); !ok { - return nil, fmt.Errorf("invalid dict constructor syntax: dot arg[%d] must be followed by a dict", i) - } - } else { - m[key] = args[i+1] - } + m[key] = args[i+1] } return m, nil } diff --git a/modules/templates/util_test.go b/modules/templates/util_test.go index 88b05485af0..608a8f230a8 100644 --- a/modules/templates/util_test.go +++ b/modules/templates/util_test.go @@ -18,18 +18,17 @@ func TestDict(t *testing.T) { args []any want map[string]any }{ + {nil, M{}}, + {[]any{"a", nil}, M{"a": nil}}, {[]any{"a", 1, "b", 2}, M{"a": 1, "b": 2}}, - {[]any{".", M{"base": 1}, "b", 2}, M{"base": 1, "b": 2}}, - {[]any{"a", 1, ".", M{"extra": 2}}, M{"a": 1, "extra": 2}}, - {[]any{"a", 1, ".", map[string]int{"int": 2}}, M{"a": 1, "int": 2}}, - {[]any{".", nil, "b", 2}, M{"b": 2}}, + {[]any{"a", 1, "a", 2}, M{"a": 2}}, + {[]any{"nested", map[string]int{"int": 2}}, M{"nested": map[string]int{"int": 2}}}, } for _, c := range cases { got, err := dict(c.args...) - if assert.NoError(t, err) { - assert.Equal(t, c.want, got) - } + assert.NoError(t, err) + assert.Equal(t, c.want, got) } bads := []struct { @@ -38,6 +37,7 @@ func TestDict(t *testing.T) { {[]any{"a", 1, "b"}}, {[]any{1}}, {[]any{struct{}{}}}, + {[]any{1, "value"}}, } for _, c := range bads { _, err := dict(c.args...) diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index ad7fc8906b6..65914bc117f 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -142,12 +142,13 @@ const ( MaxFullFileHighlightTimeLimit = 2 * time.Second ) -// GetType returns the type of DiffLine. -func (d *DiffLine) GetType() int { - return int(d.Type) -} +func (d *DiffLine) IsDiffLinePlain() bool { return d.Type == DiffLinePlain } +func (d *DiffLine) IsDiffLineAdd() bool { return d.Type == DiffLineAdd } +func (d *DiffLine) IsDiffLineDel() bool { return d.Type == DiffLineDel } +func (d *DiffLine) IsDiffLineSection() bool { return d.Type == DiffLineSection } -// GetHTMLDiffLineType returns the diff line type name for HTML +// GetHTMLDiffLineType returns the diff line type name for HTML, +// it will generate CSS names for styles ".del-code", ".add-code", ".same-code", ".tag-code" func (d *DiffLine) GetHTMLDiffLineType() string { switch d.Type { case DiffLineAdd: diff --git a/templates/repo/diff/blob_excerpt.tmpl b/templates/repo/diff/blob_excerpt.tmpl index a2dcf0d0910..da6c6cd9f55 100644 --- a/templates/repo/diff/blob_excerpt.tmpl +++ b/templates/repo/diff/blob_excerpt.tmpl @@ -1,9 +1,9 @@ {{$diffBlobExcerptData := .DiffBlobExcerptData}} {{$canCreateComment := and ctx.RootData.SignedUserID $diffBlobExcerptData.PullIssueIndex}} {{if $.IsSplitStyle}} - {{range $k, $line := $.section.Lines}} - - {{if eq .GetType 4}} + {{range $line := $.section.Lines}} + + {{if $line.IsDiffLineSection}} {{$line.RenderBlobExcerptButtons $.FileNameHash $diffBlobExcerptData}} {{- $inlineDiff := $.section.GetComputedInlineDiffFor $line ctx.Locale -}} @@ -17,7 +17,7 @@ {{/* ATTENTION: BLOB-EXCERPT-COMMENT-RIGHT: here it intentionally use "right" side to comment, because the backend code depends on the assumption that the comment only happens on right side*/}} {{- if and $canCreateComment $line.RightIdx -}} - {{- end -}} @@ -32,7 +32,7 @@ {{if $line.RightIdx}}{{end}} {{- if and $canCreateComment $line.RightIdx -}} - {{- end -}} @@ -48,21 +48,21 @@ {{if eq $line.GetCommentSide "previous"}} - {{template "repo/diff/conversation" dict "." $ "comments" $line.Comments}} + {{template "repo/diff/conversation" dict "comments" $line.Comments}} {{end}} {{if eq $line.GetCommentSide "proposed"}} - {{template "repo/diff/conversation" dict "." $ "comments" $line.Comments}} + {{template "repo/diff/conversation" dict "comments" $line.Comments}} {{end}} {{end}} {{end}} {{else}} - {{range $k, $line := $.section.Lines}} - - {{if eq .GetType 4}} + {{range $line := $.section.Lines}} + + {{if $line.IsDiffLineSection}} {{$line.RenderBlobExcerptButtons $.FileNameHash $diffBlobExcerptData}} {{else}} @@ -83,7 +83,7 @@ {{if $line.Comments}} - {{template "repo/diff/conversation" dict "." $ "comments" $line.Comments}} + {{template "repo/diff/conversation" dict "comments" $line.Comments}} {{end}} diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index 9145c09c216..d2da9e5f39b 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -86,7 +86,7 @@ {{end}}
- {{range $i, $file := .Diff.Files}} + {{range $file := .Diff.Files}} {{/*notice: the index of Diff.Files should not be used for element ID, because the index will be restarted from 0 when doing load-more for PRs with a lot of files*/}} {{$isImage:= $file.IsBlobTypeImage}} {{$isCsv := $file.IsBlobTypeCsv}} @@ -193,9 +193,9 @@ {{else if $file.Sections}} {{if $.IsSplitStyle}} - {{template "repo/diff/section_split" dict "file" . "root" $}} + {{template "repo/diff/section_split" dict "file" $file}} {{else}} - {{template "repo/diff/section_unified" dict "file" . "root" $}} + {{template "repo/diff/section_unified" dict "file" $file}} {{end}}
{{else if $file.IsRenamed}} diff --git a/templates/repo/diff/comment_form.tmpl b/templates/repo/diff/comment_form.tmpl index a8c209f033b..23efda9a219 100644 --- a/templates/repo/diff/comment_form.tmpl +++ b/templates/repo/diff/comment_form.tmpl @@ -1,46 +1,47 @@ -{{if and ctx.RootData.SignedUserID (not ctx.RootData.Repository.IsArchived)}} -
- - - - - +{{$root := ctx.RootData -}} +{{$replyReviewComment := $.ReplyReviewComment -}}{{/* can be nil */ -}} +{{$canAddComment := and $root.SignedUserID (not $root.Repository.IsArchived) -}} +{{if $canAddComment}} + + + + + +
{{template "shared/combomarkdowneditor" (dict "CustomInit" true - "MarkdownEditorContext" (ctx.MiscUtils.MarkdownEditorComment ctx.RootData.Repository) + "MarkdownEditorContext" (ctx.MiscUtils.MarkdownEditorComment $root.Repository) "TextareaName" "content" "TextareaPlaceholder" (ctx.Locale.Tr "repo.diff.comment.placeholder") "DropzoneParentContainer" "form" "DisableAutosize" "true" )}}
- {{if $.root.IsAttachmentEnabled}} + {{if $root.IsAttachmentEnabled}}
- {{template "repo/upload" dict "UploadOptions" ctx.RootData.UploadOptions}} + {{template "repo/upload" dict "UploadOptions" $root.UploadOptions}}
{{end}}
diff --git a/templates/repo/diff/comment_form_datahandler.tmpl b/templates/repo/diff/comment_form_datahandler.tmpl deleted file mode 100644 index d0e493488df..00000000000 --- a/templates/repo/diff/comment_form_datahandler.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -{{if $.comment}} - {{template "repo/diff/comment_form" dict "root" $.root "hidden" $.hidden "reply" $.reply "Line" $.comment.UnsignedLine "File" $.comment.TreePath "Side" $.comment.DiffSide "HasComments" true}} -{{else if $.root}} - {{template "repo/diff/comment_form" $}} -{{else}} - {{template "repo/diff/comment_form" dict "root" $}} -{{end}} diff --git a/templates/repo/diff/comments.tmpl b/templates/repo/diff/comments.tmpl index 449747f20b9..206f6b8f67a 100644 --- a/templates/repo/diff/comments.tmpl +++ b/templates/repo/diff/comments.tmpl @@ -1,46 +1,51 @@ -{{range $comment := .comments}} - -{{$createdStr:= DateUtils.TimeSince .CreatedUnix}} -
+{{$root := ctx.RootData -}} +{{$repo := $root.Repository -}} +{{$repoLink := $root.RepoLink -}} +{{$issue := $root.Issue -}} +{{$canWrite := or $root.Permission.IsAdmin $root.HasIssuesOrPullsWritePermission -}} +{{$signedUserID := or $root.SignedUserID NIL -}} +{{range $comment := $.comments}} +{{$createdStr:= DateUtils.TimeSince $comment.CreatedUnix}} +
- {{if .OriginalAuthor}} + {{if $comment.OriginalAuthor}} {{ctx.AvatarUtils.Avatar nil}} {{else}} - {{template "shared/user/avatarlink" dict "user" .Poster}} + {{template "shared/user/avatarlink" dict "user" $comment.Poster}} {{end}}
- {{if .OriginalAuthor}} + {{if $comment.OriginalAuthor}} - {{svg (MigrationIcon $.root.Repository.GetOriginalURLHostname)}} - {{.OriginalAuthor}} + {{svg (MigrationIcon $repo.GetOriginalURLHostname)}} + {{$comment.OriginalAuthor}} - {{ctx.Locale.Tr "repo.issues.commented_at" .HashTag $createdStr}} + {{ctx.Locale.Tr "repo.issues.commented_at" $comment.HashTag $createdStr}} - {{if $.root.Repository.OriginalURL}} - ({{ctx.Locale.Tr "repo.migrated_from" $.root.Repository.OriginalURL $.root.Repository.GetOriginalURLHostname}}) + {{if $repo.OriginalURL}} + ({{ctx.Locale.Tr "repo.migrated_from" $repo.OriginalURL $repo.GetOriginalURLHostname}}) {{end}} {{else}} - {{template "shared/user/namelink" .Poster}} - {{ctx.Locale.Tr "repo.issues.commented_at" .HashTag $createdStr}} + {{template "shared/user/namelink" $comment.Poster}} + {{ctx.Locale.Tr "repo.issues.commented_at" $comment.HashTag $createdStr}} {{end}}
- {{if .Invalidated}} - {{$referenceUrl := printf "%s#%s" $.root.Issue.Link .HashTag}} + {{if $comment.Invalidated}} + {{$referenceUrl := printf "%s#%s" $issue.Link $comment.HashTag}} {{ctx.Locale.Tr "repo.issues.review.outdated"}} {{end}} - {{if .Review}} - {{if eq .Review.Type 0}} + {{if $comment.Review}} + {{if eq $comment.Review.Type 0}}
{{ctx.Locale.Tr "repo.issues.review.pending"}}
@@ -50,29 +55,30 @@
{{end}} {{end}} - {{if not $.root.Repository.IsArchived}} - {{template "repo/issue/view_content/add_reaction" dict "ActionURL" (printf "%s/comments/%d/reactions" $.root.RepoLink .ID)}} + {{if not $repo.IsArchived}} + {{template "repo/issue/view_content/add_reaction" dict "ActionURL" (printf "%s/comments/%d/reactions" $repoLink $comment.ID)}} {{end}} {{template "repo/issue/view_content/context_menu" dict "ConvContentType" "issue_comment" "ConvContentPage" "pr-files" "ConvContentItem" $comment}}
-
- {{if .RenderedContent}} - {{.RenderedContent}} + {{$doerIsPoster := eq $signedUserID $comment.PosterID}} +
+ {{if $comment.RenderedContent}} + {{$comment.RenderedContent}} {{else}} {{ctx.Locale.Tr "repo.issues.no_content"}} {{end}}
-
{{.Content}}
-
- {{if .Attachments}} - {{template "repo/issue/view_content/attachments" dict "Attachments" .Attachments "RenderedContent" .RenderedContent}} +
{{$comment.Content}}
+
+ {{if $comment.Attachments}} + {{template "repo/issue/view_content/attachments" dict "Attachments" $comment.Attachments "RenderedContent" $comment.RenderedContent}} {{end}}
- {{$reactions := .Reactions.GroupByType}} + {{$reactions := $comment.Reactions.GroupByType}} {{if $reactions}} - {{template "repo/issue/view_content/reactions" dict "ActionURL" (printf "%s/comments/%d/reactions" $.root.RepoLink .ID) "Reactions" $reactions}} + {{template "repo/issue/view_content/reactions" dict "ActionURL" (printf "%s/comments/%d/reactions" $repoLink $comment.ID) "Reactions" $reactions}} {{end}}
diff --git a/templates/repo/diff/conversation.tmpl b/templates/repo/diff/conversation.tmpl index 16feaaefeb9..e0026582517 100644 --- a/templates/repo/diff/conversation.tmpl +++ b/templates/repo/diff/conversation.tmpl @@ -1,12 +1,17 @@ {{if len .comments}} - {{$comment := index .comments 0}} - {{$resolved := $comment.IsResolved}} - {{$invalid := $comment.Invalidated}} - {{$resolveDoer := $comment.ResolveDoer}} - {{$hasReview := and $comment.Review}} - {{$isReviewPending := and $hasReview (eq $comment.Review.Type 0)}} - {{$referenceUrl := printf "%s#%s" $.Issue.Link $comment.HashTag}} -
+ {{$root := ctx.RootData}} + {{$comments := $.comments}} + {{$firstComment := index $comments 0}} + {{$resolved := $firstComment.IsResolved}} + {{$invalid := $firstComment.Invalidated}} + {{$resolveDoer := $firstComment.ResolveDoer}} + {{$hasReview := and $firstComment.Review}} + {{$isReviewPending := and $hasReview (eq $firstComment.Review.Type 0)}} + {{$referenceUrl := printf "%s#%s" $root.Issue.Link $firstComment.HashTag}} + {{$canAddComment := and $root.SignedUserID (not $root.Repository.IsArchived)}} + {{$canMarkAsResolved := and $root.CanMarkConversation $hasReview (not $isReviewPending)}} + {{$repoLink := $root.RepoLink}} +
{{if $resolved}}
@@ -23,19 +28,19 @@ {{end}}
- -
{{end}} -
+
- {{template "repo/diff/comments" dict "root" $ "comments" .comments}} + {{template "repo/diff/comments" dict "comments" $comments}}
@@ -47,8 +52,8 @@ {{svg "octicon-arrow-down" 12}} {{ctx.Locale.Tr "repo.issues.next"}}
- {{if and $.CanMarkConversation $hasReview (not $isReviewPending)}} - {{end}} - {{if and $.SignedUserID (not $.Repository.IsArchived)}} + {{if $canAddComment}} {{end}}
- {{template "repo/diff/comment_form_datahandler" dict "hidden" true "reply" $comment.ReviewID "root" $ "comment" $comment}} + {{template "repo/diff/comment_form" dict "ReplyReviewComment" $firstComment}}
{{else}} diff --git a/templates/repo/diff/new_comment.tmpl b/templates/repo/diff/new_comment.tmpl index 6a71539ab01..56963e42184 100644 --- a/templates/repo/diff/new_comment.tmpl +++ b/templates/repo/diff/new_comment.tmpl @@ -1,5 +1,5 @@
- {{template "repo/diff/comment_form_datahandler" .}} + {{template "repo/diff/comment_form"}}
diff --git a/templates/repo/diff/section_split.tmpl b/templates/repo/diff/section_split.tmpl index c13b205518e..ecf3187c43d 100644 --- a/templates/repo/diff/section_split.tmpl +++ b/templates/repo/diff/section_split.tmpl @@ -1,5 +1,6 @@ -{{$file := .file}} -{{$diffBlobExcerptData := $.root.DiffBlobExcerptData}} +{{$file := $.file -}} +{{$diffBlobExcerptData := ctx.RootData.DiffBlobExcerptData -}} +{{$canAddComment := and ctx.RootData.SignedUserID $diffBlobExcerptData.PullIssueIndex -}} @@ -10,17 +11,17 @@ -{{range $j, $section := $file.Sections}} - {{range $k, $line := $section.Lines}} - {{$hasmatch := ne $line.Match -1}} - {{if or (ne .GetType 2) (not $hasmatch)}} - - {{if eq .GetType 4}} +{{range $section := $file.Sections}} + {{range $line := $section.Lines}} + {{$hasMatch := ne $line.Match -1}} + {{if or (not $line.IsDiffLineAdd) (not $hasMatch)}} + + {{if $line.IsDiffLineSection}} {{$inlineDiff := $section.GetComputedInlineDiffFor $line ctx.Locale}} {{$line.RenderBlobExcerptButtons $file.NameHash $diffBlobExcerptData}} {{ctx.RenderUtils.RenderUnicodeEscapeToggleButton $inlineDiff.EscapeStatus}} {{template "repo/diff/section_code" dict "diff" $inlineDiff}} - {{else if and (eq .GetType 3) $hasmatch}}{{/* DEL */}} + {{else if and $line.IsDiffLineDel $hasMatch}} {{$match := index $section.Lines $line.Match}} {{- $leftDiff := ""}}{{if $line.LeftIdx}}{{$leftDiff = $section.GetComputedInlineDiffFor $line ctx.Locale}}{{end}} {{- $rightDiff := ""}}{{if $match.RightIdx}}{{$rightDiff = $section.GetComputedInlineDiffFor $match ctx.Locale}}{{end}} @@ -28,8 +29,8 @@ {{if $line.LeftIdx}}{{ctx.RenderUtils.RenderUnicodeEscapeToggleButton $leftDiff.EscapeStatus}}{{end}} - {{- if and $.root.SignedUserID $.root.PageIsPullFiles -}} - {{- end -}} @@ -43,8 +44,8 @@ {{if $match.RightIdx}}{{ctx.RenderUtils.RenderUnicodeEscapeToggleButton $rightDiff.EscapeStatus}}{{end}} {{if $match.RightIdx}}{{end}} - {{- if and $.root.SignedUserID $.root.PageIsPullFiles -}} - {{- end -}} @@ -60,8 +61,8 @@ {{if $line.LeftIdx}}{{ctx.RenderUtils.RenderUnicodeEscapeToggleButton $inlineDiff.EscapeStatus}}{{end}} {{if $line.LeftIdx}}{{end}} - {{- if and $.root.SignedUserID $.root.PageIsPullFiles (not (eq .GetType 2)) -}} - {{- end -}} @@ -75,8 +76,8 @@ {{if $line.RightIdx}}{{ctx.RenderUtils.RenderUnicodeEscapeToggleButton $inlineDiff.EscapeStatus}}{{end}} {{if $line.RightIdx}}{{end}} - {{- if and $.root.SignedUserID $.root.PageIsPullFiles (not (eq .GetType 3)) -}} - {{- end -}} @@ -88,46 +89,46 @@ {{end}} - {{if and (eq .GetType 3) $hasmatch}} + {{if and $line.IsDiffLineDel $hasMatch}} {{$match := index $section.Lines $line.Match}} {{if or $line.Comments $match.Comments}} {{if $line.Comments}} {{if eq $line.GetCommentSide "previous"}} - {{template "repo/diff/conversation" dict "." $.root "comments" $line.Comments}} + {{template "repo/diff/conversation" dict "comments" $line.Comments}} {{end}} {{end}} {{if $match.Comments}} {{if eq $match.GetCommentSide "previous"}} - {{template "repo/diff/conversation" dict "." $.root "comments" $match.Comments}} + {{template "repo/diff/conversation" dict "comments" $match.Comments}} {{end}} {{end}} {{if $line.Comments}} {{if eq $line.GetCommentSide "proposed"}} - {{template "repo/diff/conversation" dict "." $.root "comments" $line.Comments}} + {{template "repo/diff/conversation" dict "comments" $line.Comments}} {{end}} {{end}} {{if $match.Comments}} {{if eq $match.GetCommentSide "proposed"}} - {{template "repo/diff/conversation" dict "." $.root "comments" $match.Comments}} + {{template "repo/diff/conversation" dict "comments" $match.Comments}} {{end}} {{end}} {{end}} {{else if $line.Comments}} - + {{if eq $line.GetCommentSide "previous"}} - {{template "repo/diff/conversation" dict "." $.root "comments" $line.Comments}} + {{template "repo/diff/conversation" dict "comments" $line.Comments}} {{end}} {{if eq $line.GetCommentSide "proposed"}} - {{template "repo/diff/conversation" dict "." $.root "comments" $line.Comments}} + {{template "repo/diff/conversation" dict "comments" $line.Comments}} {{end}} diff --git a/templates/repo/diff/section_unified.tmpl b/templates/repo/diff/section_unified.tmpl index 4dee648cddd..8781cabfcc1 100644 --- a/templates/repo/diff/section_unified.tmpl +++ b/templates/repo/diff/section_unified.tmpl @@ -1,6 +1,7 @@ -{{$file := .file}} +{{$file := $.file}} {{/* this tmpl is also used by the PR Conversation page, so "DiffBlobExcerptData" may not exist */}} -{{$diffBlobExcerptData := $.root.DiffBlobExcerptData}} +{{$diffBlobExcerptData := ctx.RootData.DiffBlobExcerptData}} +{{$canAddComment := and ctx.RootData.SignedUserID $diffBlobExcerptData.PullIssueIndex}} @@ -8,10 +9,10 @@ -{{range $j, $section := $file.Sections}} - {{range $k, $line := $section.Lines}} - - {{if eq .GetType 4}} +{{range $section := $file.Sections}} + {{range $line := $section.Lines}} + + {{if $line.IsDiffLineSection}} {{if $diffBlobExcerptData}} {{$line.RenderBlobExcerptButtons $file.NameHash $diffBlobExcerptData}} {{else}} @@ -27,11 +28,11 @@ {{ctx.RenderUtils.RenderUnicodeEscapeToggleButton $inlineDiff.EscapeStatus}} - {{if eq .GetType 4}} + {{if $line.IsDiffLineSection}} {{template "repo/diff/section_code" dict "diff" $inlineDiff}} {{else}} - {{- if and $.root.SignedUserID $.root.PageIsPullFiles -}} + {{- if $canAddComment -}} @@ -41,9 +42,9 @@ {{end}} {{if $line.Comments}} - + - {{template "repo/diff/conversation" dict "." $.root "comments" $line.Comments}} + {{template "repo/diff/conversation" dict "comments" $line.Comments}} {{end}} diff --git a/templates/repo/editor/diff_preview.tmpl b/templates/repo/editor/diff_preview.tmpl index fd543a5ab96..60fc730e8ca 100644 --- a/templates/repo/editor/diff_preview.tmpl +++ b/templates/repo/editor/diff_preview.tmpl @@ -4,7 +4,7 @@
- {{template "repo/diff/section_unified" dict "file" .File "root" $}} + {{template "repo/diff/section_unified" dict "file" .File}}
diff --git a/templates/repo/issue/fields/textarea.tmpl b/templates/repo/issue/fields/textarea.tmpl index 6041d5bffdd..2c5b5aad5d5 100644 --- a/templates/repo/issue/fields/textarea.tmpl +++ b/templates/repo/issue/fields/textarea.tmpl @@ -1,4 +1,5 @@ -{{$useMarkdownEditor := not .item.Attributes.render}} +{{$root := ctx.RootData -}} +{{$useMarkdownEditor := not .item.Attributes.render -}}
{{template "repo/issue/fields/header" .}} @@ -9,15 +10,15 @@ {{template "shared/combomarkdowneditor" (dict "CustomInit" true "ContainerClasses" "tw-hidden" - "MarkdownEditorContext" (ctx.MiscUtils.MarkdownEditorComment ctx.RootData.Repository) + "MarkdownEditorContext" (ctx.MiscUtils.MarkdownEditorComment $root.Repository) "TextareaContent" .item.Attributes.value "TextareaPlaceholder" .item.Attributes.placeholder "DropzoneParentContainer" ".combo-editor-dropzone" )}} - {{if .root.IsAttachmentEnabled}} + {{if $root.IsAttachmentEnabled}}
{{/*TODO: need to refactor the "repo/upload" template and remove this wrapper */}} - {{template "repo/upload" dict "UploadOptions" ctx.RootData.UploadOptions}} + {{template "repo/upload" dict "UploadOptions" $root.UploadOptions}}
{{end}} {{end}} diff --git a/templates/repo/issue/list.tmpl b/templates/repo/issue/list.tmpl index 9aa75500e02..0d0d8e71f2e 100644 --- a/templates/repo/issue/list.tmpl +++ b/templates/repo/issue/list.tmpl @@ -53,7 +53,7 @@ {{template "repo/issue/filter_actions" .}}
- {{template "shared/issuelist" dict "." . "listType" "repo"}} + {{template "shared/issuelist" dict "listType" "repo"}}
{{template "base/footer" .}} diff --git a/templates/repo/issue/milestone_issues.tmpl b/templates/repo/issue/milestone_issues.tmpl index 03cadfd295d..a82dc24607a 100644 --- a/templates/repo/issue/milestone_issues.tmpl +++ b/templates/repo/issue/milestone_issues.tmpl @@ -59,7 +59,7 @@ {{template "repo/issue/filters" .}} - {{template "shared/issuelist" dict "." . "listType" "milestone"}} + {{template "shared/issuelist" dict "listType" "milestone"}} {{template "base/footer" .}} diff --git a/templates/repo/issue/new_form.tmpl b/templates/repo/issue/new_form.tmpl index 8794827363e..d8e30b81e4c 100644 --- a/templates/repo/issue/new_form.tmpl +++ b/templates/repo/issue/new_form.tmpl @@ -22,7 +22,7 @@ {{else if eq .Type "markdown"}} {{template "repo/issue/fields/markdown" dict "item" .}} {{else if eq .Type "textarea"}} - {{template "repo/issue/fields/textarea" dict "item" . "root" $}} + {{template "repo/issue/fields/textarea" dict "item" .}} {{else if eq .Type "dropdown"}} {{template "repo/issue/fields/dropdown" dict "item" .}} {{else if eq .Type "checkboxes"}} diff --git a/templates/repo/issue/sidebar/issue_dependencies.tmpl b/templates/repo/issue/sidebar/issue_dependencies.tmpl index 82214c72714..93aa55b6aa2 100644 --- a/templates/repo/issue/sidebar/issue_dependencies.tmpl +++ b/templates/repo/issue/sidebar/issue_dependencies.tmpl @@ -137,7 +137,7 @@

{{$ModalButtonCancelText := ctx.Locale.Tr "repo.issues.dependency.cancel"}} {{$ModalButtonOkText := ctx.Locale.Tr "repo.issues.dependency.remove"}} - {{template "base/modal_actions_confirm" (dict "." . "ModalButtonCancelText" $ModalButtonCancelText "ModalButtonOkText" $ModalButtonOkText)}} + {{template "base/modal_actions_confirm" (dict "ModalButtonCancelText" $ModalButtonCancelText "ModalButtonOkText" $ModalButtonOkText)}} {{end}} diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index b82ebade71f..853a7d47022 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -454,7 +454,7 @@
{{range $filename, $lines := .Review.CodeComments}} {{range $line, $comms := $lines}} - {{template "repo/issue/view_content/conversation" dict "." $ "comments" $comms}} + {{template "repo/issue/view_content/conversation" dict "comments" $comms}} {{end}} {{end}}
diff --git a/templates/repo/issue/view_content/conversation.tmpl b/templates/repo/issue/view_content/conversation.tmpl index 030315d039d..4689cd7cbf5 100644 --- a/templates/repo/issue/view_content/conversation.tmpl +++ b/templates/repo/issue/view_content/conversation.tmpl @@ -1,15 +1,22 @@ -{{/* FIXME: DIFF-CONVERSATION-DATA: in the future this template should be refactor to avoid called by {{... "." $}} -At the moment, two kinds of request handler call this template: +{{/* TODO: At the moment, two kinds of request handler call this template: * ExcerptBlob -> blob_excerpt.tmpl -> this * Other compare and diff pages -> ... -> {section_unified.tmpl|section_split.tmpl} -> this) The variables in "ctx.Data" are different in each case, making this template fragile, hard to read and maintain. */}} {{if len .comments}} - {{$firstComment := index .comments 0}} - {{$invalid := $firstComment.Invalidated}} - {{$resolved := $firstComment.IsResolved}} - {{$resolveDoer := $firstComment.ResolveDoer}} - {{$hasReview := and $firstComment.Review}} - {{$isReviewPending := and $hasReview (eq $firstComment.Review.Type 0)}} + {{$firstComment := index .comments 0 -}} + {{$invalid := $firstComment.Invalidated -}} + {{$resolved := $firstComment.IsResolved -}} + {{$resolveDoer := $firstComment.ResolveDoer -}} + {{$hasReview := and $firstComment.Review -}} + {{$isReviewPending := and $hasReview (eq $firstComment.Review.Type 0) -}} + {{$root := ctx.RootData -}} + {{$repo := $root.Repository -}} + {{$repoLink := $root.RepoLink -}} + {{$editorconfig := $root.Editorconfig -}} + {{$canWrite := or $root.Permission.IsAdmin $root.HasIssuesOrPullsWritePermission -}} + {{$signedUserID := or $root.SignedUserID NIL -}} + {{$canMarkAsResolved := and $root.CanMarkConversation $hasReview (not $isReviewPending)}} + {{$canAddComment := and $root.SignedUserID (not $root.Repository.IsArchived)}}
@@ -30,7 +37,7 @@ The variables in "ctx.Data" are different in each case, making this template fra {{ctx.Locale.Tr "repo.issues.review.show_outdated"}} {{end}} - {{end}} - {{if and $.SignedUserID (not $.Repository.IsArchived)}} + {{if $canAddComment}} {{end}}
- {{template "repo/diff/comment_form_datahandler" dict "hidden" true "reply" $firstComment.ReviewID "root" $ "comment" $firstComment}} + {{template "repo/diff/comment_form" dict "ReplyReviewComment" $firstComment}}
{{else}} diff --git a/templates/shared/issuelist.tmpl b/templates/shared/issuelist.tmpl index c363171a3ff..2655ea57361 100644 --- a/templates/shared/issuelist.tmpl +++ b/templates/shared/issuelist.tmpl @@ -1,117 +1,119 @@ +{{$root := ctx.RootData -}} +{{$listType := .listType -}}
- {{$approvalCounts := .ApprovalCounts}} - {{range .Issues}} + {{$approvalCounts := $root.ApprovalCounts}} + {{range $issue := $root.Issues}}
{{/* using some tw helpers is the only way to align the checkbox */}}
- {{if $.CanWriteIssuesOrPulls}} - + {{if $root.CanWriteIssuesOrPulls}} + {{end}} - {{template "shared/issueicon" .}} + {{template "shared/issueicon" $issue}}
- {{.Title | ctx.RenderUtils.RenderIssueSimpleTitle}} - {{if .IsPull}} - {{if (index $.CommitStatuses .PullRequest.ID)}} + {{$issue.Title | ctx.RenderUtils.RenderIssueSimpleTitle}} + {{if $issue.IsPull}} + {{if (index $root.CommitStatuses $issue.PullRequest.ID)}} {{/* make the "flex" children align with parent "inline" */}} - {{template "repo/commit_statuses" dict "Status" (index $.CommitLastStatus .PullRequest.ID) "Statuses" (index $.CommitStatuses .PullRequest.ID)}} + {{template "repo/commit_statuses" dict "Status" (index $root.CommitLastStatus $issue.PullRequest.ID) "Statuses" (index $root.CommitStatuses $issue.PullRequest.ID)}} {{end}} {{end}} - {{- range .Labels -}} - {{ctx.RenderUtils.RenderLabel .}} + {{- range $label := $issue.Labels -}} + {{ctx.RenderUtils.RenderLabel $label}} {{- end -}}
- {{if .TotalTrackedTime}} + {{if $issue.TotalTrackedTime}}
{{svg "octicon-clock" 16}} - {{.TotalTrackedTime | Sec2Hour}} + {{$issue.TotalTrackedTime | Sec2Hour}}
{{end}}
- - {{if eq $.listType "dashboard"}} - {{.Repo.FullName}}#{{.Index}} + + {{if eq $listType "dashboard"}} + {{$issue.Repo.FullName}}#{{$issue.Index}} {{else}} - #{{.Index}} + #{{$issue.Index}} {{end}}
- {{$timeStr := DateUtils.TimeSince .GetLastEventTimestamp}} - {{if .OriginalAuthor}} - {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr .OriginalAuthor}} - {{else if gt .Poster.ID 0}} - {{ctx.Locale.Tr .GetLastEventLabel $timeStr .Poster.HomeLink .Poster.GetDisplayName}} + {{$timeStr := DateUtils.TimeSince $issue.GetLastEventTimestamp}} + {{if $issue.OriginalAuthor}} + {{ctx.Locale.Tr $issue.GetLastEventLabelFake $timeStr $issue.OriginalAuthor}} + {{else if gt $issue.Poster.ID 0}} + {{ctx.Locale.Tr $issue.GetLastEventLabel $timeStr $issue.Poster.HomeLink $issue.Poster.GetDisplayName}} {{else}} - {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr .Poster.GetDisplayName}} + {{ctx.Locale.Tr $issue.GetLastEventLabelFake $timeStr $issue.Poster.GetDisplayName}} {{end}}
- {{if .IsPull}} + {{if $issue.IsPull}} {{end}} - {{if and .Milestone (ne $.listType "milestone")}} - + {{if and $issue.Milestone (ne $listType "milestone")}} + {{svg "octicon-milestone" 14}} - {{.Milestone.Name}} + {{$issue.Milestone.Name}} {{end}} - {{range $project := .Projects}} + {{range $project := $issue.Projects}} {{svg $project.IconName 14}} {{$project.Title}} {{end}} - {{if .Ref}}{{/* TODO: ISSUE-SIDEBAR-REF-SELECTOR: see "repo/issue/branch_selector_field.tmpl" */}} - + {{if $issue.Ref}}{{/* TODO: ISSUE-SIDEBAR-REF-SELECTOR: see "repo/issue/branch_selector_field.tmpl" */}} + {{svg "octicon-git-branch" 14}} - {{index $.IssueRefEndNames .ID}} + {{index $root.IssueRefEndNames $issue.ID}} {{end}} - {{$tasks := .GetTasks}} + {{$tasks := $issue.GetTasks}} {{if gt $tasks 0}} - {{$tasksDone := .GetTasksDone}} + {{$tasksDone := $issue.GetTasksDone}} {{svg "octicon-checklist" 14}}{{$tasksDone}} / {{$tasks}} {{end}} - {{if ne .DeadlineUnix 0}} - + {{if ne $issue.DeadlineUnix 0}} + {{svg "octicon-calendar" 14}} - {{DateUtils.AbsoluteShort .DeadlineUnix}} + {{DateUtils.AbsoluteShort $issue.DeadlineUnix}} {{end}} - {{if .IsPull}} - {{$approveOfficial := call $approvalCounts .ID "approve"}} - {{$rejectOfficial := call $approvalCounts .ID "reject"}} - {{$waitingOfficial := call $approvalCounts .ID "waiting"}} + {{if $issue.IsPull}} + {{$approveOfficial := call $approvalCounts $issue.ID "approve"}} + {{$rejectOfficial := call $approvalCounts $issue.ID "reject"}} + {{$waitingOfficial := call $approvalCounts $issue.ID "waiting"}} {{if gt $approveOfficial 0}} {{svg "octicon-check" 14}} @@ -130,30 +132,30 @@ {{ctx.Locale.TrN $waitingOfficial "repo.pulls.waiting_count_1" "repo.pulls.waiting_count_n" $waitingOfficial}} {{end}} - {{if and (not .PullRequest.HasMerged) .PullRequest.ConflictedFiles}} + {{if and (not $issue.PullRequest.HasMerged) $issue.PullRequest.ConflictedFiles}} {{svg "octicon-x" 14}} - {{ctx.Locale.TrN (len .PullRequest.ConflictedFiles) "repo.pulls.num_conflicting_files_1" "repo.pulls.num_conflicting_files_n" (len .PullRequest.ConflictedFiles)}} + {{ctx.Locale.TrN (len $issue.PullRequest.ConflictedFiles) "repo.pulls.num_conflicting_files_1" "repo.pulls.num_conflicting_files_n" (len $issue.PullRequest.ConflictedFiles)}} {{end}} {{end}}
- {{if or .Assignees .NumComments}} + {{if or $issue.Assignees $issue.NumComments}}
- {{if .Assignees}} + {{if $issue.Assignees}} {{end}} - {{if .NumComments}} + {{if $issue.NumComments}} {{end}} @@ -166,10 +168,10 @@

{{ctx.Locale.Tr "repo.issues.filter_no_results_placeholder"}}

{{end}} - {{if .IssueIndexerUnavailable}} + {{if $root.IssueIndexerUnavailable}}

{{ctx.Locale.Tr "search.keyword_search_unavailable"}}

{{end}}
-{{template "base/paginate" .}} +{{template "base/paginate" $root}} diff --git a/templates/shared/search/code/results.tmpl b/templates/shared/search/code/results.tmpl index 38283ce234f..21373b9c5f8 100644 --- a/templates/shared/search/code/results.tmpl +++ b/templates/shared/search/code/results.tmpl @@ -29,7 +29,7 @@
{{template "shared/searchfile" dict "RepoLink" $repo.Link "SearchResult" .}}
- {{template "shared/searchbottom" dict "root" $ "result" .}} + {{template "shared/searchbottom" dict "result" .}}
{{end}} diff --git a/templates/user/dashboard/issues.tmpl b/templates/user/dashboard/issues.tmpl index 09f35767366..196a44246e7 100644 --- a/templates/user/dashboard/issues.tmpl +++ b/templates/user/dashboard/issues.tmpl @@ -106,7 +106,7 @@ - {{template "shared/issuelist" dict "." . "listType" "dashboard"}} + {{template "shared/issuelist" dict "listType" "dashboard"}} diff --git a/templates/user/notification/notification_subscriptions.tmpl b/templates/user/notification/notification_subscriptions.tmpl index 038a107ebcd..a1b5877b28e 100644 --- a/templates/user/notification/notification_subscriptions.tmpl +++ b/templates/user/notification/notification_subscriptions.tmpl @@ -64,7 +64,7 @@ {{if not .Issues}} {{ctx.Locale.Tr "notification.no_subscriptions"}} {{else}} - {{template "shared/issuelist" dict "." . "listType" "dashboard"}} + {{template "shared/issuelist" dict "listType" "dashboard"}} {{end}} {{else}} {{template "shared/repo/search" .}} diff --git a/tests/e2e/pr-review.test.ts b/tests/e2e/pr-review.test.ts index d2db212bbb3..ba07fa455c9 100644 --- a/tests/e2e/pr-review.test.ts +++ b/tests/e2e/pr-review.test.ts @@ -94,6 +94,9 @@ test('pr review flow', async ({page, request}) => { const conversation = fileBox.locator('.conversation-holder'); await conversation.locator('.comment-form-reply').click(); const replyForm = conversation.locator('form'); + await replyForm.getByRole('button', {name: 'Cancel', exact: true}).click(); + await expect(replyForm).toBeHidden(); + await conversation.locator('.comment-form-reply').click(); await replyForm.locator('textarea[name="content"]').fill('my reply body'); await replyForm.getByRole('button', {name: 'Reply', exact: true}).click(); await expect(conversation.locator('.comment-body')).toContainText(['inline to reply to', 'my reply body']); @@ -103,6 +106,9 @@ test('pr review flow', async ({page, request}) => { await page.goto(`${pullUrl}/files`); await fileBox.locator('tr.add-code').nth(1).getByRole('button', {name: 'Add line comment', exact: true}).click(); const pendingForm = fileBox.locator('form').filter({has: page.getByRole('button', {name: 'Start review', exact: true})}); + await pendingForm.getByRole('button', {name: 'Cancel', exact: true}).click(); + await expect(pendingForm).toHaveCount(0); + await fileBox.locator('tr.add-code').nth(1).getByRole('button', {name: 'Add line comment', exact: true}).click(); await pendingForm.getByRole('textbox', {name: 'Leave a comment', exact: true}).fill('pending review comment'); await pendingForm.getByRole('button', {name: 'Start review', exact: true}).click(); const counter = page.locator('.review-box-button .review-comments-counter'); diff --git a/tests/integration/issue_test.go b/tests/integration/issue_test.go index ccc730326e3..c1a2429ce96 100644 --- a/tests/integration/issue_test.go +++ b/tests/integration/issue_test.go @@ -62,7 +62,39 @@ func TestNoLoginViewIssues(t *testing.T) { defer tests.PrepareTestEnv(t)() req := NewRequest(t, "GET", "/user2/repo1/issues") - MakeRequest(t, req, http.StatusOK) + resp := MakeRequest(t, req, http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + issue := htmlDoc.doc.Find("#issue-list .list-item-large-title[href='/user2/repo1/issues/1']").Closest(".item") + assert.Equal(t, "label1", strings.TrimSpace(issue.Find(".labels-list").Text())) + assignee := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + assert.Equal(t, assignee.HomeLink(), issue.Find(".assignee").AttrOr("href", "")) + assert.Equal(t, assignee.GetDisplayName(), issue.Find(".assignee").AttrOr("data-tooltip-content", "")) +} + +func TestViewIssueListContexts(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + session := loginUser(t, "user2") + t.Run("dashboard", func(t *testing.T) { + req := NewRequest(t, "GET", "/issues") + resp := session.MakeRequest(t, req, http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + assert.Equal(t, "user2/repo1#1", strings.TrimSpace(htmlDoc.doc.Find("#issue-list .index[href='/user2/repo1/issues/1']").Text())) + }) + t.Run("milestone", func(t *testing.T) { + req := NewRequest(t, "GET", "/user2/repo1/milestone/1") + resp := session.MakeRequest(t, req, http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + assert.Equal(t, 1, getIssuesSelection(t, htmlDoc).Length()) + assert.Empty(t, htmlDoc.doc.Find("#issue-list .milestone").Nodes) + labels := htmlDoc.doc.Find("#issue-list .labels-list a") + assert.Equal(t, 2, labels.Length()) + labels.Each(func(_ int, label *goquery.Selection) { + link, err := url.Parse(label.AttrOr("href", "")) + assert.NoError(t, err) + assert.NotContains(t, link.Query(), "milestone") + }) + }) } func TestViewIssuesSortByType(t *testing.T) {