Add thread actions to the overview conversations
Adds thread actions to the Conversations card: reply, resolve, reopen, and a footer to add a new comment. With the classic thread list hidden, this footer is the only way left to add a general comment from the Overview tab. Code snippets and Apply come next, in !257872 (merged).
Stacked on !257879 (merged), which is merging; this MR moves to master once it does. Next in the stack: !257872 (merged).
The card with Reply and Resolve on the open threads, opening on Needs action:
All: Reopen thread on the resolved thread, no buttons on comments, and the Add a comment footer:
Reply open on the first thread:
Detailed context for AI agents
Chain
Merged:
- !252481 (merged) - flag, toggle, empty container
- !255057 (merged) - data layer
- !252997 (merged) - merge readiness
- !252998 (merged) - reviewers and recommended reviewers
- !252999 (merged) - description
- !257511 (merged) - labels and milestone, merged 2026-09-25
- !257492 (merged) - risk assessment, merged 2026-09-29
- !257832 (merged) - conversations card: the thread list, merged 2026-09-30
Open:
- !257879 (merged) - filters, roles and file links, approved and merging
- !257871 (merged) - thread actions, stacked on !257879 (merged) (this MR)
- !257872 (merged) - code snippets and suggestions, stacked on this MR
- !258493 (merged) - collapse toggle for the card, stacked on !257872 (merged)
The conversations work (!257832 (merged), !257879 (merged), !257871 (merged), !257872 (merged)) was split into four MRs on request, to keep each one reviewable. Each is stacked on the one before it.
Rebase notes (2026-10-01)
Rebased onto the reviewed head of !257879 (merged) (e1265469). That review changed the panel's shape, and this MR follows it:
discussions_panel.vuetakes the merge request as a prop and keeps its own Apollo result asconnection. ThecreateNotepermission the Reply and Add a comment buttons need is therefore asked for in the main overview query (mr_ai_overview.query.graphql, next toupdateMergeRequest), not in the panel's own query. Only the per-threadreplyIdanduserPermissions.resolveNoteare added to the discussions query.- The discussion fields are now a shared fragment (
mr_ai_overview_discussion.fragment.graphql) so thecreateNotemutation can return the full discussion and write it into the Apollo cache. - Replies are already
{ note, role }pairs frombuildDiscussion, so the template did not need theroleForcall it had before. - Strings are plain
__(), matching the earlier parts, so none carry theAiOverview|namespace. - The spec passes the merge request as a prop; the no-permission case passes one with
createNote: false. locale/gitlab.potregenerated: only the three new strings.replyIdanduserPermissions.resolveNoteon 100 threads a page push the static complexity check from 244 to 262, soee/spec/graphql/all_queries_spec.rbgets an override at 263. The check prices the resolver withsortandsearchset; the real query scores 233 of the 300 limit on GDK.
Thread actions
- Open threads (resolvable and unresolved) show small tertiary "Reply" and "Resolve" buttons under the thread. Resolved threads show "Reopen thread" instead. Comments that cannot be resolved show no buttons.
- "Reply" swaps the buttons for an inline form (
conversation_form.vue): a plain textarea with the "Reply…" placeholder, focused on open, plus "Reply" (disabled while empty) and "Cancel". It posts with the existingcreateNotemutation, passing the thread'sreplyIdasdiscussionId. - A footer under the list has "Add a comment", which opens the same form with a "Write a comment…" placeholder and a "Comment" button, and posts a new top-level comment with
createNoteand nodiscussionId. - After a reply is posted, the mutation returns the thread and the panel writes it into the Apollo cache, so the reply appears without a refetch. A new comment is appended the same way when every page is loaded; when pages remain, it belongs after threads not loaded yet, so only then is the list refetched.
- Resolve and Reopen use the existing
discussionToggleResolvemutation. The returned discussion updates the Apollo cache in place, so the row's state pill and the "N open" count change without a refetch. The resolve service also fires the merge status subscription, which the main overview already follows. - Buttons only show when allowed: Reply and "Add a comment" need the merge request's
userPermissions.createNote; Resolve and Reopen need the thread'suserPermissions.resolveNote. - Failures raise an alert: "Could not update the thread." for resolve/reopen (the thread stays as it was), and "Could not post your comment." for reply/comment (the form stays open with the text).
Left out of this MR
- The reply/comment textarea is plain, not the full markdown editor: no live preview, attachments, or quick-action autocomplete.
- Creating a task from the footer. "Add a comment" posts a plain comment; the design's "Add a comment or task" footer also offers a task, which is not included here.
Strings
Three new strings: Add a comment, Could not post your comment., Could not update the thread..
Reused: Reply, Resolve, Reopen thread, Cancel, Comment, Reply…, Write a comment….
Files changed (11)
ee/app/assets/javascripts/merge_requests/ai_overview/components/conversation_form.vue- new.ee/app/assets/javascripts/merge_requests/ai_overview/components/discussions_panel.vue- now also owns the thread actions.ee/app/assets/javascripts/merge_requests/ai_overview/queries/mr_ai_overview.query.graphql- asks forcreateNote.ee/app/assets/javascripts/merge_requests/ai_overview/queries/mr_ai_overview_create_note.mutation.graphql- new.ee/app/assets/javascripts/merge_requests/ai_overview/queries/mr_ai_overview_toggle_resolve.mutation.graphql- new.ee/app/assets/javascripts/merge_requests/ai_overview/queries/mr_ai_overview_discussions.query.graphql- asks forreplyIdandresolveNote.ee/app/assets/javascripts/merge_requests/ai_overview/queries/mr_ai_overview_discussion.fragment.graphql- new, the discussion fields shared by the query and thecreateNotemutation.ee/spec/features/merge_request/user_toggles_ai_overview_spec.rb- adds: resolving a thread from its row, after switching to All, shows "Reopen thread" and resolves the note in the database.ee/spec/frontend/merge_requests/ai_overview/components/conversation_form_spec.js- new, 5 examples.ee/spec/frontend/merge_requests/ai_overview/components/discussions_panel_spec.js- adds actions shown per thread state, resolve, reopen, reply form, reply posted into the thread, cancel, add comment appended, add comment with pages left refetches, resolve failure, post failure, no permission and no empty actions row.ee/spec/frontend/merge_requests/ai_overview/mock_data.js-replyId, threaduserPermissions,createNoteon the merge request mock.locale/gitlab.pot.
Verification performed
- After the rebase: Jest
ee/spec/frontend/merge_requests/ai_overview, 10 suites, 162 examples, all pass. ESLint, Prettier and Rubocop clean. - The screenshots above were taken on GDK after the rebase, with no console errors: Needs action, All, and the Reply form open.
- Before the rebase (2026-09-25), on GDK: Resolve turned the pill to Resolved, swapped the buttons for "Reopen thread", and dropped the count from 3 open to 2. Reopen reversed it. Reply posted and appeared under the thread. "Add a comment" posted a new thread with a "Comment" pill. The mutations and their handlers are unchanged by the rebase, so this was not repeated.
- The two mutations passed schema validation on GDK. The query's complexity was 233 of 300 in a signed-in page before the context fields moved to the main query, so it is lower now.
- The feature spec is CI-only, as before.


