feat(ui): create a comment aggregator to reduce noise in issues (#6523)
Some checks are pending
/ release (push) Waiting to run
testing / backend-checks (push) Has been skipped
testing / frontend-checks (push) Has been skipped
testing / test-unit (push) Has been skipped
testing / test-e2e (push) Has been skipped
testing / test-mysql (push) Has been skipped
testing / test-pgsql (push) Has been skipped
testing / test-sqlite (push) Has been skipped
testing / test-remote-cacher (redis) (push) Has been skipped
testing / test-remote-cacher (valkey) (push) Has been skipped
testing / test-remote-cacher (garnet) (push) Has been skipped
testing / test-remote-cacher (redict) (push) Has been skipped
testing / security-check (push) Has been skipped

Closes: https://codeberg.org/forgejo/forgejo/issues/6042
Continuation of: https://codeberg.org/forgejo/forgejo/pulls/6284
Replaces: https://codeberg.org/forgejo/forgejo/pulls/6285
Context: https://codeberg.org/forgejo/forgejo/pulls/6284#issuecomment-2518599

Create a new type of comment: `CommentTypeAggregator`

Replaces the grouping of labels and review request in a single place: the comment aggregator

The whole list of comments is "scanned", if they can get aggregated (diff of time < 60secs, same poster, open / close issue, add / del labels, add /del review req), they are added to the aggregator.
Once needed, the list of all the aggregated comments are replaced with a single aggregated comment containing all the data required.

In templates, have a specific HTML rendering part for the comment aggregator, reuse the same rendering as with the other types of comments.

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/6523
Reviewed-by: 0ko <0ko@noreply.codeberg.org>
Reviewed-by: Otto <otto@codeberg.org>
Co-authored-by: Litchi Pi <litchi.pi@proton.me>
Co-committed-by: Litchi Pi <litchi.pi@proton.me>
This commit is contained in:
Litchi Pi 2025-03-05 17:24:51 +00:00 committed by 0ko
parent 2c27a0f727
commit dc7f5d6b84
8 changed files with 1264 additions and 1006 deletions

View file

@ -12,7 +12,7 @@
26 = DELETE_TIME_MANUAL, 27 = REVIEW_REQUEST, 28 = MERGE_PULL_REQUEST,
29 = PULL_PUSH_EVENT, 30 = PROJECT_CHANGED, 31 = PROJECT_BOARD_CHANGED
32 = DISMISSED_REVIEW, 33 = COMMENT_TYPE_CHANGE_ISSUE_REF, 34 = PR_SCHEDULE_TO_AUTO_MERGE,
35 = CANCEL_SCHEDULED_AUTO_MERGE_PR, 36 = PIN_ISSUE, 37 = UNPIN_ISSUE -->
35 = CANCEL_SCHEDULED_AUTO_MERGE_PR, 36 = PIN_ISSUE, 37 = UNPIN_ISSUE, 38 = ACTION_AGGREGATOR -->
{{if eq .Type 0}}
<div class="timeline-item comment" id="{{.HashTag}}">
{{if .OriginalAuthor}}
@ -524,7 +524,7 @@
</div>
</div>
{{else if eq .Type 27}}
{{if or .AddedRequestReview .RemovedRequestReview}}
{{if or .AddedRequestReview .RemovedRequestReview}}
<div class="timeline-item event" id="{{.HashTag}}">
<span class="badge">{{svg "octicon-tag"}}</span>
{{template "shared/user/avatarlink" dict "user" .Poster}}
@ -540,7 +540,7 @@
{{end}}
</span>
</div>
{{end}}
{{end}}
{{else if and (eq .Type 29) (or (gt .CommitsNum 0) .IsForcePush)}}
<!-- If PR is closed, the comments whose type is CommentTypePullRequestPush(29) after latestCloseCommentID won't be rendered. //-->
{{if and .Issue.IsClosed (gt .ID $.LatestCloseCommentID)}}
@ -676,6 +676,73 @@
{{else}}{{ctx.Locale.Tr "repo.issues.unpin_comment" $createdStr}}{{end}}
</span>
</div>
{{else if eq .Type 38}}
<div class="timeline-item event" id="{{.HashTag}}">
<span class="badge">{{svg "octicon-list-unordered" 16}}</span>
{{template "shared/user/avatarlink" dict "user" .Poster}}
<span class="text grey muted-links">
{{template "shared/user/authorlink" .Poster}}
{{$createdStr}}
<ul class="tw-list-none aggregated-actions">
<!-- OPEN / CLOSE -->
{{if and .Aggregator.PrevClosed (not .Aggregator.IsClosed)}}
<li>
<span class="badge tw-bg-green tw-text-white">{{svg "octicon-dot-fill"}}</span>
{{if .Issue.IsPull}}
{{ctx.Locale.Tr "repo.pulls.reopened_at" "" ""}}
{{else}}
{{ctx.Locale.Tr "repo.issues.reopened_at" "" ""}}
{{end}}
</li>
{{else if and (not .Aggregator.PrevClosed) .Aggregator.IsClosed}}
<span class="badge tw-bg-red tw-text-white">{{svg "octicon-circle-slash"}}</span>
<li>
{{if .Issue.IsPull}}
{{ctx.Locale.Tr "repo.pulls.closed_at" "" ""}}
{{else}}
{{ctx.Locale.Tr "repo.issues.closed_at" "" ""}}
{{end}}
</li>
{{end}}
<!-- Add labels -->
{{if or .AddedLabels .RemovedLabels}}
<li>
<span class="badge">{{svg "octicon-tag" 20}}</span>
{{if and .AddedLabels (not .RemovedLabels)}}
{{ctx.Locale.TrN (len .AddedLabels) "repo.issues.add_label" "repo.issues.add_labels" (RenderLabels $.Context ctx.Locale .AddedLabels $.RepoLink .Issue.IsPull) ""}}
{{else if and (not .AddedLabels) .RemovedLabels}}
{{ctx.Locale.TrN (len .RemovedLabels) "repo.issues.remove_label" "repo.issues.remove_labels" (RenderLabels $.Context ctx.Locale .RemovedLabels $.RepoLink .Issue.IsPull) ""}}
{{else}}
{{ctx.Locale.Tr "repo.issues.add_remove_labels" (RenderLabels $.Context ctx.Locale .AddedLabels $.RepoLink .Issue.IsPull) (RenderLabels $.Context ctx.Locale .RemovedLabels $.RepoLink .Issue.IsPull) ""}}
{{end}}
</li>
{{end}}
{{if or .AddedRequestReview .RemovedRequestReview}}
<li>
<span class="badge">{{svg "octicon-tag" 20}}</span>
<span class="text grey muted-links">
{{if and (eq (len .RemovedRequestReview) 1) (eq (len .AddedRequestReview) 0) (eq ((index .RemovedRequestReview 0).ID) .PosterID) (eq ((index .RemovedRequestReview 0).Type) "user")}}
<span class="review-request-list">{{ctx.Locale.Tr "repo.issues.review.remove_review_request_self" ""}}</span>
{{else if and .AddedRequestReview (not .RemovedRequestReview)}}
{{ctx.Locale.TrN (len .AddedRequestReview) "repo.issues.review.add_review_request" "repo.issues.review.add_review_requests" (RenderReviewRequest .AddedRequestReview) ""}}
{{else if and (not .AddedRequestReview) .RemovedRequestReview}}
{{ctx.Locale.TrN (len .RemovedRequestReview) "repo.issues.review.remove_review_request" "repo.issues.review.remove_review_requests" (RenderReviewRequest .RemovedRequestReview) ""}}
{{else}}
{{ctx.Locale.Tr "repo.issues.review.add_remove_review_requests" (RenderReviewRequest .AddedRequestReview) (RenderReviewRequest .RemovedRequestReview) ""}}
{{end}}
</span>
</li>
{{end}}
</ul>
</span>
</div>
{{end}}
{{end}}
{{end}}