fix(ui): show participants in mention suggestions in pr review (#8363)

Closes: #5035

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/8363
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
Co-authored-by: Lucas Schwiderski <lucas@lschwiderski.de>
Co-committed-by: Lucas Schwiderski <lucas@lschwiderski.de>
This commit is contained in:
Lucas Schwiderski 2025-09-04 23:29:34 +02:00 committed by Otto
commit 82728d903d
5 changed files with 76 additions and 3 deletions

View file

@ -237,7 +237,7 @@ func (issue *Issue) LoadPullRequest(ctx context.Context) (err error) {
return nil
}
func (issue *Issue) loadComments(ctx context.Context) (err error) {
func (issue *Issue) LoadComments(ctx context.Context) (err error) {
return issue.loadCommentsByType(ctx, CommentTypeUndefined)
}
@ -341,7 +341,7 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) {
return err
}
if err = issue.loadComments(ctx); err != nil {
if err = issue.LoadComments(ctx); err != nil {
return err
}

View file

@ -84,7 +84,7 @@ func searchIssueWithKeyword(t *testing.T) {
issueIDs, _, err := SearchIssues(t.Context(), &test.opts)
require.NoError(t, err)
assert.Equal(t, test.expectedIDs, issueIDs)
assert.Equal(t, test.expectedIDs, issueIDs, test.opts.Keyword)
}
}

View file

@ -3777,3 +3777,49 @@ func issuePosters(ctx *context.Context, isPullList bool) {
}
ctx.JSON(http.StatusOK, resp)
}
func getIssueParticipants(ctx *context.Context, issue *issues_model.Issue) []*user_model.User {
var (
participants = make([]*user_model.User, 1, 10)
comment *issues_model.Comment
)
participants[0] = issue.Poster
if err := issue.LoadComments(ctx); err != nil {
ctx.ServerError("loadComments", err)
return nil
}
if err := issue.Comments.LoadPosters(ctx); err != nil {
ctx.ServerError("LoadPosters", err)
return nil
}
for _, comment = range issue.Comments {
if comment.Type == issues_model.CommentTypeComment ||
comment.Type == issues_model.CommentTypeReview ||
comment.Type == issues_model.CommentTypePullRequestPush {
participants = addParticipant(comment.Poster, participants)
} else if comment.Type.HasContentSupport() {
participants = addParticipant(comment.Poster, participants)
if comment.Review == nil {
continue
}
if err := comment.Review.LoadCodeComments(ctx); err != nil {
ctx.ServerError("Review.LoadCodeComments", err)
return nil
}
for _, codeComments := range comment.Review.CodeComments {
for _, lineComments := range codeComments {
for _, c := range lineComments {
participants = addParticipant(c.Poster, participants)
}
}
}
}
}
return participants
}

View file

@ -1167,6 +1167,13 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi
}
ctx.Data["Assignees"] = MakeSelfOnTop(ctx.Doer, assigneeUsers)
participants := getIssueParticipants(ctx, issue)
if ctx.Written() {
return
}
ctx.Data["Participants"] = participants
ctx.Data["NumParticipants"] = len(participants)
handleTeamMentions(ctx)
if ctx.Written() {
return

View file

@ -112,3 +112,23 @@ test('PR: Navigate by single commit', async ({page}) => {
await expect(nextButton).toHaveClass(/disabled/);
await expect(prevButton).toHaveAttribute('href', '/user2/repo1/pulls/3/commits/4a357436d925b5c974181ff12a994538ddc5a269');
});
test('PR: Test mentions values', async ({page}) => {
const response = await page.goto('/user2/repo1/pulls/5/files');
expect(response?.status()).toBe(200);
await page.locator('#review-box .js-btn-review').click();
await expect(page.locator('.tippy-box .review-box-panel')).toBeVisible();
await page.locator('.review-box-panel textarea#_combo_markdown_editor_0')
.fill('@');
await save_visual(page);
await expect(page.locator('ul.suggestions li span:first-of-type')).toContainText([
'user1',
'user2',
]);
await page.locator("ul.suggestions li[data-value='@user1']").click();
await expect(page.locator('.review-box-panel textarea#_combo_markdown_editor_0')).toHaveValue('@user1 ');
});