Fix showing outdated discussions on Changes tab
This commit is contained in:
parent
489025bbdd
commit
7632330e50
15 changed files with 146 additions and 20 deletions
|
@ -77,7 +77,8 @@ export default {
|
|||
diffViewType: state => state.diffs.diffViewType,
|
||||
diffFiles: state => state.diffs.diffFiles,
|
||||
}),
|
||||
...mapGetters(['isLoggedIn', 'discussionsByLineCode']),
|
||||
...mapGetters(['isLoggedIn']),
|
||||
...mapGetters('diffs', ['discussionsByLineCode']),
|
||||
lineHref() {
|
||||
return this.lineCode ? `#${this.lineCode}` : '#';
|
||||
},
|
||||
|
|
|
@ -26,13 +26,16 @@ export default {
|
|||
...mapState({
|
||||
diffLineCommentForms: state => state.diffs.diffLineCommentForms,
|
||||
}),
|
||||
...mapGetters(['discussionsByLineCode']),
|
||||
...mapGetters('diffs', ['discussionsByLineCode']),
|
||||
discussions() {
|
||||
return this.discussionsByLineCode[this.line.lineCode] || [];
|
||||
},
|
||||
className() {
|
||||
return this.discussions.length ? '' : 'js-temp-notes-holder';
|
||||
},
|
||||
hasCommentForm() {
|
||||
return this.diffLineCommentForms[this.line.lineCode];
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -53,7 +56,7 @@ export default {
|
|||
:discussions="discussions"
|
||||
/>
|
||||
<diff-line-note-form
|
||||
v-if="diffLineCommentForms[line.lineCode]"
|
||||
v-if="hasCommentForm"
|
||||
:diff-file-hash="diffFileHash"
|
||||
:line="line"
|
||||
:note-target-line="line"
|
||||
|
|
|
@ -20,8 +20,7 @@ export default {
|
|||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('diffs', ['commitId']),
|
||||
...mapGetters(['discussionsByLineCode']),
|
||||
...mapGetters('diffs', ['commitId', 'discussionsByLineCode']),
|
||||
...mapState({
|
||||
diffLineCommentForms: state => state.diffs.diffLineCommentForms,
|
||||
}),
|
||||
|
|
|
@ -26,7 +26,7 @@ export default {
|
|||
...mapState({
|
||||
diffLineCommentForms: state => state.diffs.diffLineCommentForms,
|
||||
}),
|
||||
...mapGetters(['discussionsByLineCode']),
|
||||
...mapGetters('diffs', ['discussionsByLineCode']),
|
||||
leftLineCode() {
|
||||
return this.line.left.lineCode;
|
||||
},
|
||||
|
|
|
@ -21,8 +21,7 @@ export default {
|
|||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('diffs', ['commitId']),
|
||||
...mapGetters(['discussionsByLineCode']),
|
||||
...mapGetters('diffs', ['commitId', 'discussionsByLineCode']),
|
||||
...mapState({
|
||||
diffLineCommentForms: state => state.diffs.diffLineCommentForms,
|
||||
}),
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import _ from 'underscore';
|
||||
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||
import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '../constants';
|
||||
import { getDiffRefsByLineCode } from './utils';
|
||||
|
||||
export const isParallelView = state => state.diffViewType === PARALLEL_DIFF_VIEW_TYPE;
|
||||
|
||||
|
@ -56,6 +58,44 @@ export const getDiffFileDiscussions = (state, getters, rootState, rootGetters) =
|
|||
discussion.diff_discussion && _.isEqual(discussion.diff_file.file_hash, diff.fileHash),
|
||||
) || [];
|
||||
|
||||
/**
|
||||
* Returns an Object with discussions by their diff line code
|
||||
* To avoid rendering outdated discussions on the Changes tab we should do a bunch of SHA
|
||||
* comparisions. `note.position.formatter` have the current version diff refs but
|
||||
* `note.original_position.formatter` will have the first version's diff refs.
|
||||
* If line diff refs matches with one of them, we should render it as a discussion on Changes tab.
|
||||
*
|
||||
* @param {Object} diff
|
||||
* @returns {Array}
|
||||
*/
|
||||
export const discussionsByLineCode = (state, getters, rootState, rootGetters) => {
|
||||
const diffRefsByLineCode = getDiffRefsByLineCode(state.diffFiles);
|
||||
|
||||
return rootGetters.discussions.reduce((acc, note) => {
|
||||
const isDiffDiscussion = note.diff_discussion;
|
||||
const hasLineCode = note.line_code;
|
||||
const isResolvable = note.resolvable;
|
||||
const diffRefs = diffRefsByLineCode[note.line_code];
|
||||
|
||||
if (isDiffDiscussion && hasLineCode && isResolvable && diffRefs) {
|
||||
const refs = convertObjectPropsToCamelCase(note.position.formatter);
|
||||
const originalRefs = convertObjectPropsToCamelCase(note.original_position.formatter);
|
||||
|
||||
if (_.isEqual(refs, diffRefs) || _.isEqual(originalRefs, diffRefs)) {
|
||||
const lineCode = note.line_code;
|
||||
|
||||
if (acc[lineCode]) {
|
||||
acc[lineCode].push(note);
|
||||
} else {
|
||||
acc[lineCode] = [note];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
};
|
||||
|
||||
// prevent babel-plugin-rewire from generating an invalid default during karma∂ tests
|
||||
export const getDiffFileByHash = state => fileHash =>
|
||||
state.diffFiles.find(file => file.fileHash === fileHash);
|
||||
|
|
|
@ -173,3 +173,24 @@ export function trimFirstCharOfLineContent(line = {}) {
|
|||
|
||||
return parsedLine;
|
||||
}
|
||||
|
||||
export function getDiffRefsByLineCode(diffFiles) {
|
||||
return diffFiles.reduce((acc, diffFile) => {
|
||||
const { baseSha, headSha, startSha } = diffFile.diffRefs;
|
||||
const { newPath, oldPath } = diffFile;
|
||||
|
||||
// We can only use highlightedDiffLines to create the map of diff lines because
|
||||
// highlightedDiffLines will also include every parallel diff line in it.
|
||||
if (diffFile.highlightedDiffLines) {
|
||||
diffFile.highlightedDiffLines.forEach(line => {
|
||||
const { lineCode, oldLine, newLine } = line;
|
||||
|
||||
if (lineCode) {
|
||||
acc[lineCode] = { baseSha, headSha, startSha, newPath, oldPath, oldLine, newLine };
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
|
|
@ -28,18 +28,6 @@ export const notesById = state =>
|
|||
return acc;
|
||||
}, {});
|
||||
|
||||
export const discussionsByLineCode = state =>
|
||||
state.discussions.reduce((acc, note) => {
|
||||
if (note.diff_discussion && note.line_code && note.resolvable) {
|
||||
// For context about line notes: there might be multiple notes with the same line code
|
||||
const items = acc[note.line_code] || [];
|
||||
items.push(note);
|
||||
|
||||
Object.assign(acc, { [note.line_code]: items });
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
export const noteableType = state => {
|
||||
const { ISSUE_NOTEABLE_TYPE, MERGE_REQUEST_NOTEABLE_TYPE, EPIC_NOTEABLE_TYPE } = constants;
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ class DiscussionEntity < Grape::Entity
|
|||
|
||||
expose :id, :reply_id
|
||||
expose :position, if: -> (d, _) { d.diff_discussion? && !d.legacy_diff_discussion? }
|
||||
expose :original_position, if: -> (d, _) { d.diff_discussion? && !d.legacy_diff_discussion? }
|
||||
expose :line_code, if: -> (d, _) { d.diff_discussion? }
|
||||
expose :expanded?, as: :expanded
|
||||
expose :active?, as: :active, if: -> (d, _) { d.diff_discussion? }
|
||||
|
|
5
changelogs/unreleased/_acet-fix-outdated-discussions.yml
Normal file
5
changelogs/unreleased/_acet-fix-outdated-discussions.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix showing outdated discussions on Changes tab
|
||||
merge_request: 20445
|
||||
author:
|
||||
type: fixed
|
|
@ -18,10 +18,12 @@ describe('DiffLineGutterContent', () => {
|
|||
};
|
||||
const setDiscussions = component => {
|
||||
component.$store.dispatch('setInitialNotes', getDiscussionsMockData());
|
||||
component.$store.commit('diffs/SET_DIFF_DATA', { diffFiles: [getDiffFileMock()] });
|
||||
};
|
||||
|
||||
const resetDiscussions = component => {
|
||||
component.$store.dispatch('setInitialNotes', []);
|
||||
component.$store.commit('diffs/SET_DIFF_DATA', {});
|
||||
};
|
||||
|
||||
describe('computed', () => {
|
||||
|
|
|
@ -33,6 +33,7 @@ describe('InlineDiffView', () => {
|
|||
it('should render discussions', done => {
|
||||
const el = component.$el;
|
||||
component.$store.dispatch('setInitialNotes', getDiscussionsMockData());
|
||||
component.$store.commit('diffs/SET_DIFF_DATA', { diffFiles: [getDiffFileMock()] });
|
||||
|
||||
Vue.nextTick(() => {
|
||||
expect(el.querySelectorAll('.notes_holder').length).toEqual(1);
|
||||
|
|
|
@ -12,6 +12,17 @@ export default {
|
|||
head_sha: 'c48ee0d1bf3b30453f5b32250ce03134beaa6d13',
|
||||
},
|
||||
},
|
||||
original_position: {
|
||||
formatter: {
|
||||
old_line: null,
|
||||
new_line: 2,
|
||||
old_path: 'CHANGELOG',
|
||||
new_path: 'CHANGELOG',
|
||||
base_sha: 'e63f41fe459e62e1228fcef60d7189127aeba95a',
|
||||
start_sha: 'd9eaefe5a676b820c57ff18cf5b68316025f7962',
|
||||
head_sha: 'c48ee0d1bf3b30453f5b32250ce03134beaa6d13',
|
||||
},
|
||||
},
|
||||
line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2',
|
||||
expanded: true,
|
||||
notes: [
|
||||
|
|
|
@ -2,6 +2,7 @@ import * as getters from '~/diffs/store/getters';
|
|||
import state from '~/diffs/store/modules/diff_state';
|
||||
import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '~/diffs/constants';
|
||||
import discussion from '../mock_data/diff_discussions';
|
||||
import diffFile from '../mock_data/diff_file';
|
||||
|
||||
describe('Diffs Module Getters', () => {
|
||||
let localState;
|
||||
|
@ -203,4 +204,38 @@ describe('Diffs Module Getters', () => {
|
|||
expect(getters.getDiffFileByHash(localState)('123')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('discussionsByLineCode', () => {
|
||||
let mockState;
|
||||
|
||||
beforeEach(() => {
|
||||
mockState = { diffFiles: [diffFile] };
|
||||
});
|
||||
|
||||
it('should return a map of diff lines with their line codes', () => {
|
||||
const mockGetters = { discussions: [discussionMock] };
|
||||
|
||||
const map = getters.discussionsByLineCode(mockState, {}, {}, mockGetters);
|
||||
expect(map['1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2']).toBeDefined();
|
||||
expect(Object.keys(map).length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should have the diff discussion on the map if the original position matches', () => {
|
||||
discussionMock.position.formatter.base_sha = 'ff9200';
|
||||
const mockGetters = { discussions: [discussionMock] };
|
||||
|
||||
const map = getters.discussionsByLineCode(mockState, {}, {}, mockGetters);
|
||||
expect(map['1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2']).toBeDefined();
|
||||
expect(Object.keys(map).length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should not add an outdated diff discussion to the returned map', () => {
|
||||
discussionMock.position.formatter.base_sha = 'ff9200';
|
||||
discussionMock.original_position.formatter.base_sha = 'ff9200';
|
||||
const mockGetters = { discussions: [discussionMock] };
|
||||
|
||||
const map = getters.discussionsByLineCode(mockState, {}, {}, mockGetters);
|
||||
expect(Object.keys(map).length).toEqual(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -207,4 +207,24 @@ describe('DiffsStoreUtils', () => {
|
|||
expect(utils.trimFirstCharOfLineContent()).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDiffRefsByLineCode', () => {
|
||||
it('should return diffRefs for all highlightedDiffLines', () => {
|
||||
const diffFile = getDiffFileMock();
|
||||
const map = utils.getDiffRefsByLineCode([diffFile]);
|
||||
const { highlightedDiffLines } = diffFile;
|
||||
const lineCodeCount = highlightedDiffLines.reduce(
|
||||
(acc, line) => (line.lineCode ? acc + 1 : acc),
|
||||
0,
|
||||
);
|
||||
|
||||
const { baseSha, headSha, startSha } = diffFile.diffRefs;
|
||||
const targetLine = map[highlightedDiffLines[4].lineCode];
|
||||
|
||||
expect(Object.keys(map).length).toEqual(lineCodeCount);
|
||||
expect(targetLine.baseSha).toEqual(baseSha);
|
||||
expect(targetLine.headSha).toEqual(headSha);
|
||||
expect(targetLine.startSha).toEqual(startSha);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue