diff --git a/app/assets/javascripts/diffs/stores/legacy_diffs/actions.js b/app/assets/javascripts/diffs/stores/legacy_diffs/actions.js index 14db30db975141afc7a0448ed549de940a28fa17..17e6f378fa2532c2d86b9c79a3a3b8e1a1e4fc3e 100644 --- a/app/assets/javascripts/diffs/stores/legacy_diffs/actions.js +++ b/app/assets/javascripts/diffs/stores/legacy_diffs/actions.js @@ -59,6 +59,7 @@ import { EVT_MR_PREPARED, FILE_DIFF_POSITION_TYPE, EVT_DISCUSSIONS_ASSIGNED, + OLD_LINE_TYPE, } from '../../constants'; import { DISCUSSION_SINGLE_DIFF_FAILED, @@ -662,6 +663,48 @@ export async function saveDiffDiscussion({ note, formData }) { }); } +export function getLinesForDiscussion({ discussion }) { + const lines = []; + + if (!discussion?.diff_file || !discussion?.position) { + return lines; + } + + const diffFile = this.diffFiles.find((file) => file.file_hash === discussion.diff_file.file_hash); + + if (!diffFile) { + return lines; + } + + const diffLines = diffFile[INLINE_DIFF_LINES_KEY]; + let isAdding = false; + const { start, end } = discussion.position?.line_range || {}; + + if (!start || !end) { + return lines; + } + + for (let i = 0, diffLinesLength = diffLines.length - 1; i <= diffLinesLength; i += 1) { + const line = diffLines[i]; + + if (start.line_code === line.line_code) { + isAdding = true; + } + + if (isAdding) { + if (line.type !== OLD_LINE_TYPE) { + lines.push(line); + } + + if (end.line_code === line.line_code) { + break; + } + } + } + + return lines; +} + export function toggleTreeOpen(path) { this[types.TOGGLE_FOLDER_OPEN](path); } diff --git a/spec/frontend/diffs/stores/legacy_diffs/actions_spec.js b/spec/frontend/diffs/stores/legacy_diffs/actions_spec.js index 57f6fe18ea37f322d9539645d762a34b232456d7..22580b98e7c3e31f1aed2069c9b12cf889ae3e0e 100644 --- a/spec/frontend/diffs/stores/legacy_diffs/actions_spec.js +++ b/spec/frontend/diffs/stores/legacy_diffs/actions_spec.js @@ -9,9 +9,11 @@ import { getDiffFileMock } from 'jest/diffs/mock_data/diff_file'; import { DIFF_VIEW_COOKIE_NAME, INLINE_DIFF_VIEW_TYPE, + INLINE_DIFF_LINES_KEY, PARALLEL_DIFF_VIEW_TYPE, EVT_MR_PREPARED, FILE_DIFF_POSITION_TYPE, + OLD_LINE_TYPE, } from '~/diffs/constants'; import { BUILDING_YOUR_MR, @@ -1321,6 +1323,137 @@ describe('legacyDiffs actions', () => { }); }); + describe('getLinesForDiscussion', () => { + it('returns empty array when discussion is null or undefined', () => { + expect(store.getLinesForDiscussion({ discussion: null })).toEqual([]); + expect(store.getLinesForDiscussion({ discussion: undefined })).toEqual([]); + }); + + it('returns empty array when discussion has no position', () => { + const result = store.getLinesForDiscussion({ discussion: {} }); + expect(result).toEqual([]); + }); + + it('returns empty array when line_range is missing', () => { + const discussion = { position: {} }; + const result = store.getLinesForDiscussion({ discussion }); + expect(result).toEqual([]); + }); + + it('returns empty array when diffFile is not found', () => { + const discussion = { + diff_file: { file_hash: 'nonexistent_hash' }, + position: { + line_range: { + start: { line_code: 'start_line' }, + end: { line_code: 'end_line' }, + }, + }, + }; + + store.diffFiles = [{ file_hash: 'different_hash' }]; + + const result = store.getLinesForDiscussion({ discussion }); + expect(result).toEqual([]); + }); + + it('returns correct lines for a valid discussion', () => { + const diffLines = [ + { line_code: 'line1', type: 'new' }, + { line_code: 'line2', type: 'new' }, + { line_code: 'line3', type: 'new' }, + { line_code: 'line4', type: 'new' }, + { line_code: 'line5', type: 'new' }, + ]; + + const diffFile = { + file_hash: 'abc123', + [INLINE_DIFF_LINES_KEY]: diffLines, + }; + + const discussion = { + diff_file: { file_hash: 'abc123' }, + position: { + line_range: { + start: { line_code: 'line2' }, + end: { line_code: 'line4' }, + }, + }, + }; + + store.diffFiles = [diffFile]; + + const result = store.getLinesForDiscussion({ discussion }); + expect(result).toEqual([ + { line_code: 'line2', type: 'new' }, + { line_code: 'line3', type: 'new' }, + { line_code: 'line4', type: 'new' }, + ]); + }); + + it('excludes old lines from the result', () => { + const diffLines = [ + { line_code: 'line1', type: 'new' }, + { line_code: 'line2', type: OLD_LINE_TYPE }, + { line_code: 'line3', type: 'new' }, + { line_code: 'line4', type: OLD_LINE_TYPE }, + { line_code: 'line5', type: 'new' }, + ]; + + const diffFile = { + file_hash: 'abc123', + [INLINE_DIFF_LINES_KEY]: diffLines, + }; + + const discussion = { + diff_file: { file_hash: 'abc123' }, + position: { + line_range: { + start: { line_code: 'line1' }, + end: { line_code: 'line5' }, + }, + }, + }; + + store.diffFiles = [diffFile]; + + const result = store.getLinesForDiscussion({ discussion }); + expect(result).toEqual([ + { line_code: 'line1', type: 'new' }, + { line_code: 'line3', type: 'new' }, + { line_code: 'line5', type: 'new' }, + ]); + }); + + it('handles case when start and end are the same line', () => { + const diffLines = [ + { line_code: 'line1', type: 'new' }, + { line_code: 'line2', type: 'new' }, + { line_code: 'line3', type: 'new' }, + ]; + + const diffFile = { + file_hash: 'abc123', + [INLINE_DIFF_LINES_KEY]: diffLines, + }; + + const discussion = { + diff_file: { file_hash: 'abc123' }, + position: { + line_range: { + start: { line_code: 'line2' }, + end: { line_code: 'line2' }, + }, + }, + }; + + store.diffFiles = [diffFile]; + + const result = store.getLinesForDiscussion({ discussion }); + expect(result).toEqual([{ line_code: 'line2', type: 'new' }]); + }); + }); + describe('toggleTreeOpen', () => { it('commits TOGGLE_FOLDER_OPEN', () => { return testAction(