Trim first char of diff line text on diff discussions

Before, diff file `higlighted_diff_lines`/`parallel_diff_lines` and
diff discussion `truncated_diff_lines` were inconsistent: `text` and
`rich_text` on the latter included the leading +/-/<space> character,
like on the backend, while the former had no `text` and its `rich_text`
had dropped this char.

This resulted in a bug when the suggestions feature expected these diff
line objects to be identical in format and thus interchangeable, which
was not the case.
This commit is contained in:
Douwe Maan 2019-01-22 13:35:28 +01:00
parent ed1da73020
commit 03df54b226
No known key found for this signature in database
GPG key ID: 5976703F65143D36
8 changed files with 40 additions and 24 deletions

View file

@ -181,8 +181,6 @@ export function addContextLines(options) {
export function trimFirstCharOfLineContent(line = {}) { export function trimFirstCharOfLineContent(line = {}) {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
delete line.text; delete line.text;
// eslint-disable-next-line no-param-reassign
line.discussions = [];
const parsedLine = Object.assign({}, line); const parsedLine = Object.assign({}, line);
@ -222,10 +220,12 @@ export function prepareDiffData(diffData) {
line.line_code = getLineCode(line, u); line.line_code = getLineCode(line, u);
if (line.left) { if (line.left) {
line.left = trimFirstCharOfLineContent(line.left); line.left = trimFirstCharOfLineContent(line.left);
line.left.discussions = [];
line.left.hasForm = false; line.left.hasForm = false;
} }
if (line.right) { if (line.right) {
line.right = trimFirstCharOfLineContent(line.right); line.right = trimFirstCharOfLineContent(line.right);
line.right.discussions = [];
line.right.hasForm = false; line.right.hasForm = false;
} }
} }
@ -235,7 +235,11 @@ export function prepareDiffData(diffData) {
const linesLength = file.highlighted_diff_lines.length; const linesLength = file.highlighted_diff_lines.length;
for (let u = 0; u < linesLength; u += 1) { for (let u = 0; u < linesLength; u += 1) {
const line = file.highlighted_diff_lines[u]; const line = file.highlighted_diff_lines[u];
Object.assign(line, { ...trimFirstCharOfLineContent(line), hasForm: false }); Object.assign(line, {
...trimFirstCharOfLineContent(line),
discussions: [],
hasForm: false,
});
} }
showingLines += file.parallel_diff_lines.length; showingLines += file.parallel_diff_lines.length;
} }

View file

@ -6,8 +6,6 @@ import ImageDiffOverlay from '~/diffs/components/image_diff_overlay.vue';
import { GlSkeletonLoading } from '@gitlab/ui'; import { GlSkeletonLoading } from '@gitlab/ui';
import { getDiffMode } from '~/diffs/store/utils'; import { getDiffMode } from '~/diffs/store/utils';
const FIRST_CHAR_REGEX = /^(\+|-| )/;
export default { export default {
components: { components: {
DiffFileHeader, DiffFileHeader,
@ -54,9 +52,6 @@ export default {
this.error = true; this.error = true;
}); });
}, },
trimChar(line) {
return line.replace(FIRST_CHAR_REGEX, '');
},
}, },
userColorSchemeClass: window.gon.user_color_scheme, userColorSchemeClass: window.gon.user_color_scheme,
}; };
@ -85,7 +80,7 @@ export default {
> >
<td class="diff-line-num old_line">{{ line.old_line }}</td> <td class="diff-line-num old_line">{{ line.old_line }}</td>
<td class="diff-line-num new_line">{{ line.new_line }}</td> <td class="diff-line-num new_line">{{ line.new_line }}</td>
<td :class="line.type" class="line_content" v-html="trimChar(line.rich_text)"></td> <td :class="line.type" class="line_content" v-html="line.rich_text"></td>
</tr> </tr>
</template> </template>
<tr v-if="!hasTruncatedDiffLines" class="line_holder line-holder-placeholder"> <tr v-if="!hasTruncatedDiffLines" class="line_holder line-holder-placeholder">

View file

@ -206,11 +206,15 @@ export default {
return sprintf(text, { commitId, linkStart, linkEnd }, false); return sprintf(text, { commitId, linkStart, linkEnd }, false);
}, },
diffLine() { diffLine() {
if (this.line) {
return this.line;
}
if (this.discussion.diff_discussion && this.discussion.truncated_diff_lines) { if (this.discussion.diff_discussion && this.discussion.truncated_diff_lines) {
return this.discussion.truncated_diff_lines.slice(-1)[0]; return this.discussion.truncated_diff_lines.slice(-1)[0];
} }
return this.line; return null;
}, },
}, },
watch: { watch: {

View file

@ -105,7 +105,10 @@ export default {
if (discussion.diff_file) { if (discussion.diff_file) {
diffData.file_hash = discussion.diff_file.file_hash; diffData.file_hash = discussion.diff_file.file_hash;
diffData.truncated_diff_lines = discussion.truncated_diff_lines || [];
diffData.truncated_diff_lines = utils.prepareDiffLines(
discussion.truncated_diff_lines || [],
);
} }
// To support legacy notes, should be very rare case. // To support legacy notes, should be very rare case.
@ -243,7 +246,7 @@ export default {
[types.SET_DISCUSSION_DIFF_LINES](state, { discussionId, diffLines }) { [types.SET_DISCUSSION_DIFF_LINES](state, { discussionId, diffLines }) {
const discussion = utils.findNoteObjectById(state.discussions, discussionId); const discussion = utils.findNoteObjectById(state.discussions, discussionId);
discussion.truncated_diff_lines = diffLines; discussion.truncated_diff_lines = utils.prepareDiffLines(diffLines);
}, },
[types.DISABLE_COMMENTS](state, value) { [types.DISABLE_COMMENTS](state, value) {

View file

@ -1,4 +1,5 @@
import AjaxCache from '~/lib/utils/ajax_cache'; import AjaxCache from '~/lib/utils/ajax_cache';
import { trimFirstCharOfLineContent } from '~/diffs/store/utils';
const REGEX_QUICK_ACTIONS = /^\/\w+.*$/gm; const REGEX_QUICK_ACTIONS = /^\/\w+.*$/gm;
@ -28,3 +29,6 @@ export const getQuickActionText = note => {
export const hasQuickActions = note => REGEX_QUICK_ACTIONS.test(note); export const hasQuickActions = note => REGEX_QUICK_ACTIONS.test(note);
export const stripQuickActions = note => note.replace(REGEX_QUICK_ACTIONS, '').trim(); export const stripQuickActions = note => note.replace(REGEX_QUICK_ACTIONS, '').trim();
export const prepareDiffLines = diffLines =>
diffLines.map(line => ({ ...trimFirstCharOfLineContent(line) }));

View file

@ -0,0 +1,5 @@
---
title: Fix bug that caused Suggestion Markdown toolbar button to insert snippet with leading +/-/<space>
merge_request:
author:
type: fixed

View file

@ -251,45 +251,40 @@ describe('DiffsStoreUtils', () => {
describe('trimFirstCharOfLineContent', () => { describe('trimFirstCharOfLineContent', () => {
it('trims the line when it starts with a space', () => { it('trims the line when it starts with a space', () => {
expect(utils.trimFirstCharOfLineContent({ rich_text: ' diff' })).toEqual({ expect(utils.trimFirstCharOfLineContent({ rich_text: ' diff' })).toEqual({
discussions: [],
rich_text: 'diff', rich_text: 'diff',
}); });
}); });
it('trims the line when it starts with a +', () => { it('trims the line when it starts with a +', () => {
expect(utils.trimFirstCharOfLineContent({ rich_text: '+diff' })).toEqual({ expect(utils.trimFirstCharOfLineContent({ rich_text: '+diff' })).toEqual({
discussions: [],
rich_text: 'diff', rich_text: 'diff',
}); });
}); });
it('trims the line when it starts with a -', () => { it('trims the line when it starts with a -', () => {
expect(utils.trimFirstCharOfLineContent({ rich_text: '-diff' })).toEqual({ expect(utils.trimFirstCharOfLineContent({ rich_text: '-diff' })).toEqual({
discussions: [],
rich_text: 'diff', rich_text: 'diff',
}); });
}); });
it('does not trims the line when it starts with a letter', () => { it('does not trims the line when it starts with a letter', () => {
expect(utils.trimFirstCharOfLineContent({ rich_text: 'diff' })).toEqual({ expect(utils.trimFirstCharOfLineContent({ rich_text: 'diff' })).toEqual({
discussions: [],
rich_text: 'diff', rich_text: 'diff',
}); });
}); });
it('does not modify the provided object', () => { it('does not modify the provided object', () => {
const lineObj = { const lineObj = {
discussions: [],
rich_text: ' diff', rich_text: ' diff',
}; };
utils.trimFirstCharOfLineContent(lineObj); utils.trimFirstCharOfLineContent(lineObj);
expect(lineObj).toEqual({ discussions: [], rich_text: ' diff' }); expect(lineObj).toEqual({ rich_text: ' diff' });
}); });
it('handles a undefined or null parameter', () => { it('handles a undefined or null parameter', () => {
expect(utils.trimFirstCharOfLineContent()).toEqual({ discussions: [] }); expect(utils.trimFirstCharOfLineContent()).toEqual({});
}); });
}); });

View file

@ -179,11 +179,11 @@ describe('Notes Store mutations', () => {
diff_file: { diff_file: {
file_hash: 'a', file_hash: 'a',
}, },
truncated_diff_lines: ['a'], truncated_diff_lines: [{ text: '+a', rich_text: '+<span>a</span>' }],
}, },
]); ]);
expect(state.discussions[0].truncated_diff_lines).toEqual(['a']); expect(state.discussions[0].truncated_diff_lines).toEqual([{ rich_text: '<span>a</span>' }]);
}); });
it('adds empty truncated_diff_lines when not in discussion', () => { it('adds empty truncated_diff_lines when not in discussion', () => {
@ -420,9 +420,12 @@ describe('Notes Store mutations', () => {
], ],
}; };
mutations.SET_DISCUSSION_DIFF_LINES(state, { discussionId: 1, diffLines: ['test'] }); mutations.SET_DISCUSSION_DIFF_LINES(state, {
discussionId: 1,
diffLines: [{ text: '+a', rich_text: '+<span>a</span>' }],
});
expect(state.discussions[0].truncated_diff_lines).toEqual(['test']); expect(state.discussions[0].truncated_diff_lines).toEqual([{ rich_text: '<span>a</span>' }]);
}); });
it('keeps reactivity of discussion', () => { it('keeps reactivity of discussion', () => {
@ -435,7 +438,10 @@ describe('Notes Store mutations', () => {
]); ]);
const discussion = state.discussions[0]; const discussion = state.discussions[0];
mutations.SET_DISCUSSION_DIFF_LINES(state, { discussionId: 1, diffLines: ['test'] }); mutations.SET_DISCUSSION_DIFF_LINES(state, {
discussionId: 1,
diffLines: [{ rich_text: '<span>a</span>' }],
});
discussion.expanded = true; discussion.expanded = true;