From 17ad214c8c2984d8739e9c183af653da15fff8b3 Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Fri, 22 Aug 2025 20:24:59 -0600 Subject: [PATCH 1/2] Pass the correct lines to the reply box for multi-line comments Changelog: fixed --- .../javascripts/notes/components/noteable_discussion.vue | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue index 8d65585f760a69..5063f0c7d00899 100644 --- a/app/assets/javascripts/notes/components/noteable_discussion.vue +++ b/app/assets/javascripts/notes/components/noteable_discussion.vue @@ -14,6 +14,7 @@ import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link import { detectAndConfirmSensitiveTokens } from '~/lib/utils/secret_detection'; import { FILE_DIFF_POSITION_TYPE, IMAGE_DIFF_POSITION_TYPE } from '~/diffs/constants'; import { useNotes } from '~/notes/store/legacy_notes'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; import eventHub from '../event_hub'; import noteable from '../mixins/noteable'; import resolvable from '../mixins/resolvable'; @@ -188,6 +189,9 @@ export default { isDiscussionInternal() { return this.discussion.notes[0]?.internal; }, + commentLines() { + return this.getLinesForDiscussion({ discussion: this.discussion }); + }, discussionHolderClass() { return { 'is-replying': this.isReplying, @@ -216,6 +220,7 @@ export default { 'removeConvertedDiscussion', 'expandDiscussion', ]), + ...mapActions(useLegacyDiffs, ['getLinesForDiscussion']), showReplyForm(text) { this.isReplying = true; @@ -378,6 +383,7 @@ export default { :discussion="discussion" :diff-file="diffFile" :line="diffLine" + :lines="commentLines" :save-button-title="saveButtonTitle" :autofocus="!hasDraft" :autosave-key="autosaveKey" -- GitLab From 3bfea3829ea500f4a0df647cbb8b4630a1f03fd1 Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Wed, 27 Aug 2025 12:55:53 -0600 Subject: [PATCH 2/2] Test that the correct lines are passed to the NoteForm --- .../components/noteable_discussion_spec.js | 76 +++++++++++++++++-- 1 file changed, 69 insertions(+), 7 deletions(-) diff --git a/spec/frontend/notes/components/noteable_discussion_spec.js b/spec/frontend/notes/components/noteable_discussion_spec.js index be8e86c86215e2..ab9c649a0897f9 100644 --- a/spec/frontend/notes/components/noteable_discussion_spec.js +++ b/spec/frontend/notes/components/noteable_discussion_spec.js @@ -36,10 +36,23 @@ Vue.use(PiniaVuePlugin); jest.mock('~/behaviors/markdown/render_gfm'); jest.mock('~/alert'); +function createPinia({ stubActions = true } = {}) { + const pinia = createTestingPinia({ stubActions, plugins: [globalAccessorPlugin] }); + const diffsStore = useLegacyDiffs(); + useNotes().noteableData = noteableDataMock; + useNotes().notesData = notesDataMock; + useNotes().saveNote.mockResolvedValue(); + useNotes().fetchDiscussionDiffLines.mockResolvedValue(); + useBatchComments(); + + return { pinia, diffsStore }; +} + describe('noteable_discussion component', () => { let pinia; let wrapper; let axiosMock; + let diffsStore; const createComponent = ({ discussion = discussionMock } = {}) => { wrapper = mountExtended(NoteableDiscussion, { @@ -49,13 +62,7 @@ describe('noteable_discussion component', () => { }; beforeEach(() => { - pinia = createTestingPinia({ plugins: [globalAccessorPlugin] }); - useLegacyDiffs(); - useNotes().noteableData = noteableDataMock; - useNotes().notesData = notesDataMock; - useNotes().saveNote.mockResolvedValue(); - useNotes().fetchDiscussionDiffLines.mockResolvedValue(); - useBatchComments(); + ({ pinia, diffsStore } = createPinia()); axiosMock = new MockAdapter(axios); createComponent(); }); @@ -306,6 +313,61 @@ describe('noteable_discussion component', () => { }); }); + it('includes the original line range when replying', async () => { + wrapper.vm.showReplyForm(); + + await nextTick(); + + const form = wrapper.findComponent(NoteForm); + + expect(form.props('lines')).toEqual([]); + }); + + describe('multi-line comments', () => { + let discussion; + let startCode; + let endCode; + + beforeEach(() => { + ({ pinia, diffsStore } = createPinia({ stubActions: false })); + + const file = getDiffFileMock(); + diffsStore.diffFiles = [file]; + + startCode = file.highlighted_diff_lines[6].line_code; + endCode = file.highlighted_diff_lines[7].line_code; + + discussion = { + ...discussionMock, + diff_file: file, + position: { + line_range: { + start: { + line_code: startCode, + }, + end: { + line_code: endCode, + }, + }, + }, + }; + + createComponent({ discussion }); + }); + + it('includes the original line range when replying to a multiline comment', async () => { + wrapper.vm.showReplyForm(); + await nextTick(); + + const form = wrapper.findComponent(NoteForm); + + expect(form.props('lines')).toEqual([ + expect.objectContaining({ line_code: startCode }), + expect.objectContaining({ line_code: endCode }), + ]); + }); + }); + it('supports direct call on showReplyForm', async () => { const mock = jest.fn(); wrapper = mount(NoteableDiscussion, { -- GitLab