From 80a689fab83861aa412a14983411710c3f04fb15 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 19 Oct 2018 14:09:16 +0100 Subject: Impove diff discussion data Pre-request to https://gitlab.com/gitlab-org/gitlab-ce/issues/48956 --- app/assets/javascripts/diffs/components/app.vue | 16 +++-- .../javascripts/diffs/components/diff_file.vue | 4 +- app/assets/javascripts/diffs/store/actions.js | 42 ++++++++----- app/assets/javascripts/diffs/store/mutations.js | 73 +++++++++++----------- app/assets/javascripts/notes/stores/getters.js | 4 -- app/assets/javascripts/notes/stores/utils.js | 12 ---- spec/javascripts/diffs/store/actions_spec.js | 8 +-- spec/javascripts/diffs/store/mutations_spec.js | 4 +- 8 files changed, 80 insertions(+), 83 deletions(-) diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index edca45f22f9..9ddca8548e0 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -41,6 +41,11 @@ export default { required: true, }, }, + data() { + return { + assignedDiscussions: false, + }; + }, computed: { ...mapState({ isLoading: state => state.diffs.isLoading, @@ -60,7 +65,7 @@ export default { }), ...mapState('diffs', ['showTreeList']), ...mapGetters('diffs', ['isParallelView']), - ...mapGetters(['isNotesFetched', 'discussionsStructuredByLineCode']), + ...mapGetters(['isNotesFetched', 'getNoteableData']), targetBranch() { return { branchName: this.targetBranchName, @@ -147,11 +152,12 @@ export default { } }, setDiscussions() { - if (this.isNotesFetched) { + if (this.isNotesFetched && !this.assignedDiscussions) { requestIdleCallback( - () => { - this.assignDiscussionsToDiff(this.discussionsStructuredByLineCode); - }, + () => + this.assignDiscussionsToDiff().then(() => { + this.assignedDiscussions = true; + }), { timeout: 1000 }, ); } diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index f72c7a84e5c..958e57c5652 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -29,7 +29,7 @@ export default { }, computed: { ...mapState('diffs', ['currentDiffFileId']), - ...mapGetters(['isNotesFetched', 'discussionsStructuredByLineCode']), + ...mapGetters(['isNotesFetched']), isCollapsed() { return this.file.collapsed || false; }, @@ -79,7 +79,7 @@ export default { .then(() => { requestIdleCallback( () => { - this.assignDiscussionsToDiff(this.discussionsStructuredByLineCode); + this.assignDiscussionsToDiff(); }, { timeout: 1000 }, ); diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index 1e0b27b538d..e79351454ab 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -5,7 +5,6 @@ import createFlash from '~/flash'; import { s__ } from '~/locale'; import { handleLocationHash, historyPushState } from '~/lib/utils/common_utils'; import { mergeUrlParams, getLocationHash } from '~/lib/utils/url_utility'; -import { reduceDiscussionsToLineCodes } from '../../notes/stores/utils'; import { getDiffPositionByLineCode, getNoteFormData } from './utils'; import * as types from './mutation_types'; import { @@ -36,18 +35,33 @@ export const fetchDiffFiles = ({ state, commit }) => { // This is adding line discussions to the actual lines in the diff tree // once for parallel and once for inline mode -export const assignDiscussionsToDiff = ({ state, commit }, allLineDiscussions) => { +export const assignDiscussionsToDiff = ( + { commit, state, rootState }, + discussionsToAssign = rootState.notes.discussions, +) => { const diffPositionByLineCode = getDiffPositionByLineCode(state.diffFiles); - - Object.values(allLineDiscussions).forEach(discussions => { - if (discussions.length > 0) { - const { fileHash } = discussions[0]; - commit(types.SET_LINE_DISCUSSIONS_FOR_FILE, { - fileHash, - discussions, - diffPositionByLineCode, - }); - } + const discussionsByDiffFile = discussionsToAssign + .filter(discussion => discussion.diff_discussion) + .reduce((acc, discussion) => { + const discussions = ( + acc[discussion.diff_file.file_hash] || { discussions: [] } + ).discussions.concat(discussion); + + return { + ...acc, + [discussion.diff_file.file_hash]: { + diffFile: state.diffFiles.find(file => file.fileHash === discussion.diff_file.file_hash), + discussions, + }, + }; + }, {}); + + Object.values(discussionsByDiffFile).forEach(({ discussions, diffFile }) => { + commit(types.SET_LINE_DISCUSSIONS_FOR_FILE, { + diffFile, + discussions, + diffPositionByLineCode, + }); }); }; @@ -190,9 +204,7 @@ export const saveDiffDiscussion = ({ dispatch }, { note, formData }) => { return dispatch('saveNote', postData, { root: true }) .then(result => dispatch('updateDiscussion', result.discussion, { root: true })) - .then(discussion => - dispatch('assignDiscussionsToDiff', reduceDiscussionsToLineCodes([discussion])), - ) + .then(discussion => dispatch('assignDiscussionsToDiff', [discussion])) .catch(() => createFlash(s__('MergeRequests|Saving the comment failed'))); }; diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index 0b4485ecdb5..6a57a075579 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -90,53 +90,50 @@ export default { })); }, - [types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { fileHash, discussions, diffPositionByLineCode }) { - const selectedFile = state.diffFiles.find(f => f.fileHash === fileHash); - const firstDiscussion = discussions[0]; - const isDiffDiscussion = firstDiscussion.diff_discussion; - const hasLineCode = firstDiscussion.line_code; - const diffPosition = diffPositionByLineCode[firstDiscussion.line_code]; - - if ( - selectedFile && - isDiffDiscussion && - hasLineCode && - diffPosition && - isDiscussionApplicableToLine({ - discussion: firstDiscussion, - diffPosition, - latestDiff: state.latestDiff, - }) - ) { - const targetLine = selectedFile.parallelDiffLines.find( - line => - (line.left && line.left.lineCode === firstDiscussion.line_code) || - (line.right && line.right.lineCode === firstDiscussion.line_code), - ); - if (targetLine) { - if (targetLine.left && targetLine.left.lineCode === firstDiscussion.line_code) { - Object.assign(targetLine.left, { - discussions, - }); - } else { - Object.assign(targetLine.right, { - discussions, + [types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { diffFile, discussions, diffPositionByLineCode }) { + const { latestDiff } = state; + + discussions.forEach(discussion => { + const discussionLineCode = discussion.line_code; + const lineCheck = ({ lineCode }) => + lineCode === discussionLineCode && + isDiscussionApplicableToLine({ + discussion, + diffPosition: diffPositionByLineCode[lineCode], + latestDiff, + }); + + if (diffFile.highlightedDiffLines) { + const line = diffFile.highlightedDiffLines.find(lineCheck); + + if (line) { + Object.assign(line, { + discussions: line.discussions.concat(discussion), }); } } - if (selectedFile.highlightedDiffLines) { - const targetInlineLine = selectedFile.highlightedDiffLines.find( - line => line.lineCode === firstDiscussion.line_code, + if (diffFile.parallelDiffLines) { + const { left, right } = diffFile.parallelDiffLines.find( + parallelLine => + (parallelLine.left && lineCheck(parallelLine.left)) || + (parallelLine.right && lineCheck(parallelLine.right)), ); + const line = left && left.lineCode === discussionLineCode ? left : right; - if (targetInlineLine) { - Object.assign(targetInlineLine, { - discussions, + if (line) { + Object.assign(line, { + discussions: line.discussions.concat(discussion), }); } } - } + + if (!diffFile.parallelDiffLines || !diffFile.highlightedDiffLines) { + Object.assign(diffFile, { + discussions: diffFile.discussions.concat(discussion), + }); + } + }); }, [types.REMOVE_LINE_DISCUSSIONS_FOR_FILE](state, { fileHash, lineCode }) { diff --git a/app/assets/javascripts/notes/stores/getters.js b/app/assets/javascripts/notes/stores/getters.js index 21c334a9d33..e4f36154fcd 100644 --- a/app/assets/javascripts/notes/stores/getters.js +++ b/app/assets/javascripts/notes/stores/getters.js @@ -1,6 +1,5 @@ import _ from 'underscore'; import * as constants from '../constants'; -import { reduceDiscussionsToLineCodes } from './utils'; import { collapseSystemNotes } from './collapse_utils'; export const discussions = state => collapseSystemNotes(state.discussions); @@ -31,9 +30,6 @@ export const notesById = state => return acc; }, {}); -export const discussionsStructuredByLineCode = state => - reduceDiscussionsToLineCodes(state.discussions); - export const noteableType = state => { const { ISSUE_NOTEABLE_TYPE, MERGE_REQUEST_NOTEABLE_TYPE, EPIC_NOTEABLE_TYPE } = constants; diff --git a/app/assets/javascripts/notes/stores/utils.js b/app/assets/javascripts/notes/stores/utils.js index 0e41ff03d67..dd57539e4d8 100644 --- a/app/assets/javascripts/notes/stores/utils.js +++ b/app/assets/javascripts/notes/stores/utils.js @@ -25,18 +25,6 @@ export const getQuickActionText = note => { return text; }; -export const reduceDiscussionsToLineCodes = selectedDiscussions => - selectedDiscussions.reduce((acc, note) => { - if (note.diff_discussion && note.line_code) { - // 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 hasQuickActions = note => REGEX_QUICK_ACTIONS.test(note); export const stripQuickActions = note => note.replace(REGEX_QUICK_ACTIONS, '').trim(); diff --git a/spec/javascripts/diffs/store/actions_spec.js b/spec/javascripts/diffs/store/actions_spec.js index 85c1926fcb1..12db3cc6a25 100644 --- a/spec/javascripts/diffs/store/actions_spec.js +++ b/spec/javascripts/diffs/store/actions_spec.js @@ -27,7 +27,6 @@ import actions, { toggleShowTreeList, } from '~/diffs/store/actions'; import * as types from '~/diffs/store/mutation_types'; -import { reduceDiscussionsToLineCodes } from '~/notes/stores/utils'; import axios from '~/lib/utils/axios_utils'; import testAction from '../../helpers/vuex_action_helper'; @@ -152,7 +151,7 @@ describe('DiffsStoreActions', () => { original_position: diffPosition, }; - const discussions = reduceDiscussionsToLineCodes([singleDiscussion]); + const discussions = [singleDiscussion]; testAction( assignDiscussionsToDiff, @@ -162,7 +161,7 @@ describe('DiffsStoreActions', () => { { type: types.SET_LINE_DISCUSSIONS_FOR_FILE, payload: { - fileHash: 'ABC', + diffFile: state.diffFiles[0], discussions: [singleDiscussion], diffPositionByLineCode: { ABC_1_1: { @@ -581,7 +580,6 @@ describe('DiffsStoreActions', () => { describe('saveDiffDiscussion', () => { beforeEach(() => { spyOnDependency(actions, 'getNoteFormData').and.returnValue('testData'); - spyOnDependency(actions, 'reduceDiscussionsToLineCodes').and.returnValue('discussions'); }); it('dispatches actions', done => { @@ -602,7 +600,7 @@ describe('DiffsStoreActions', () => { .then(() => { expect(dispatch.calls.argsFor(0)).toEqual(['saveNote', 'testData', { root: true }]); expect(dispatch.calls.argsFor(1)).toEqual(['updateDiscussion', 'test', { root: true }]); - expect(dispatch.calls.argsFor(2)).toEqual(['assignDiscussionsToDiff', 'discussions']); + expect(dispatch.calls.argsFor(2)).toEqual(['assignDiscussionsToDiff', ['discussion']]); }) .then(done) .catch(done.fail); diff --git a/spec/javascripts/diffs/store/mutations_spec.js b/spec/javascripts/diffs/store/mutations_spec.js index b7e28391419..3a9c8f3a825 100644 --- a/spec/javascripts/diffs/store/mutations_spec.js +++ b/spec/javascripts/diffs/store/mutations_spec.js @@ -222,7 +222,7 @@ describe('DiffsStoreMutations', () => { }; mutations[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { - fileHash: 'ABC', + diffFile: state.diffFiles[0], discussions, diffPositionByLineCode, }); @@ -292,7 +292,7 @@ describe('DiffsStoreMutations', () => { }; mutations[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { - fileHash: 'ABC', + diffFile: state.diffFiles[0], discussions, diffPositionByLineCode, }); -- cgit v1.2.1 From 0fba7cca36ea352b3cd8c0e8a34a61453d2c7e07 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 25 Oct 2018 12:04:34 +0100 Subject: Update the state, not a param Also fixed a bug where discussions wouldn't be assigned to a line when switching from discussion tab to changes tab --- app/assets/javascripts/diffs/components/app.vue | 4 +- app/assets/javascripts/diffs/store/actions.js | 24 ++----- app/assets/javascripts/diffs/store/mutations.js | 85 +++++++++++++++---------- 3 files changed, 57 insertions(+), 56 deletions(-) diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 9ddca8548e0..a8d615dd8f0 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -63,7 +63,7 @@ export default { plainDiffPath: state => state.diffs.plainDiffPath, emailPatchPath: state => state.diffs.emailPatchPath, }), - ...mapState('diffs', ['showTreeList']), + ...mapState('diffs', ['showTreeList', 'isLoading']), ...mapGetters('diffs', ['isParallelView']), ...mapGetters(['isNotesFetched', 'getNoteableData']), targetBranch() { @@ -152,7 +152,7 @@ export default { } }, setDiscussions() { - if (this.isNotesFetched && !this.assignedDiscussions) { + if (this.isNotesFetched && !this.assignedDiscussions && !this.isLoading) { requestIdleCallback( () => this.assignDiscussionsToDiff().then(() => { diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index e79351454ab..ca8ae605cb4 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -37,29 +37,13 @@ export const fetchDiffFiles = ({ state, commit }) => { // once for parallel and once for inline mode export const assignDiscussionsToDiff = ( { commit, state, rootState }, - discussionsToAssign = rootState.notes.discussions, + discussions = rootState.notes.discussions, ) => { const diffPositionByLineCode = getDiffPositionByLineCode(state.diffFiles); - const discussionsByDiffFile = discussionsToAssign - .filter(discussion => discussion.diff_discussion) - .reduce((acc, discussion) => { - const discussions = ( - acc[discussion.diff_file.file_hash] || { discussions: [] } - ).discussions.concat(discussion); - - return { - ...acc, - [discussion.diff_file.file_hash]: { - diffFile: state.diffFiles.find(file => file.fileHash === discussion.diff_file.file_hash), - discussions, - }, - }; - }, {}); - - Object.values(discussionsByDiffFile).forEach(({ discussions, diffFile }) => { + + discussions.filter(discussion => discussion.diff_discussion).forEach(discussion => { commit(types.SET_LINE_DISCUSSIONS_FOR_FILE, { - diffFile, - discussions, + discussion, diffPositionByLineCode, }); }); diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index 6a57a075579..5a8aebd2086 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -90,49 +90,66 @@ export default { })); }, - [types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { diffFile, discussions, diffPositionByLineCode }) { + [types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { discussion, diffPositionByLineCode }) { const { latestDiff } = state; - discussions.forEach(discussion => { - const discussionLineCode = discussion.line_code; - const lineCheck = ({ lineCode }) => - lineCode === discussionLineCode && - isDiscussionApplicableToLine({ - discussion, - diffPosition: diffPositionByLineCode[lineCode], - latestDiff, - }); - - if (diffFile.highlightedDiffLines) { - const line = diffFile.highlightedDiffLines.find(lineCheck); - - if (line) { - Object.assign(line, { - discussions: line.discussions.concat(discussion), + const discussionLineCode = discussion.line_code; + const fileHash = discussion.diff_file.file_hash; + const lineCheck = ({ lineCode }) => + lineCode === discussionLineCode && + isDiscussionApplicableToLine({ + discussion, + diffPosition: diffPositionByLineCode[lineCode], + latestDiff, + }); + + state.diffFiles = state.diffFiles.map(diffFile => { + if (diffFile.fileHash === fileHash) { + const file = { ...diffFile }; + + if (file.highlightedDiffLines) { + file.highlightedDiffLines = file.highlightedDiffLines.map(line => { + if (lineCheck(line)) { + return { + ...line, + discussions: line.discussions.concat(discussion), + }; + } + + return line; }); } - } - - if (diffFile.parallelDiffLines) { - const { left, right } = diffFile.parallelDiffLines.find( - parallelLine => - (parallelLine.left && lineCheck(parallelLine.left)) || - (parallelLine.right && lineCheck(parallelLine.right)), - ); - const line = left && left.lineCode === discussionLineCode ? left : right; - if (line) { - Object.assign(line, { - discussions: line.discussions.concat(discussion), + if (file.parallelDiffLines) { + file.parallelDiffLines = file.parallelDiffLines.map(line => { + const left = line.left && lineCheck(line.left); + const right = line.right && lineCheck(line.right); + + if (left || right) { + return { + left: { + ...line.left, + discussions: left ? line.left.discussions.concat(discussion) : [], + }, + right: { + ...line.right, + discussions: right ? line.right.discussions.concat(discussion) : [], + }, + }; + } + + return line; }); } - } - if (!diffFile.parallelDiffLines || !diffFile.highlightedDiffLines) { - Object.assign(diffFile, { - discussions: diffFile.discussions.concat(discussion), - }); + if (!file.parallelDiffLines || !file.highlightedDiffLines) { + file.discussions = file.discussions.concat(discussion); + } + + return file; } + + return diffFile; }); }, -- cgit v1.2.1 From 81944ec925b5bf59855ada4e73a55c30ffce0b35 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 25 Oct 2018 12:57:08 +0100 Subject: Fixed action & mutation specs --- spec/javascripts/diffs/store/actions_spec.js | 3 +- spec/javascripts/diffs/store/mutations_spec.js | 70 +++++++++++--------------- 2 files changed, 29 insertions(+), 44 deletions(-) diff --git a/spec/javascripts/diffs/store/actions_spec.js b/spec/javascripts/diffs/store/actions_spec.js index 12db3cc6a25..bb623953710 100644 --- a/spec/javascripts/diffs/store/actions_spec.js +++ b/spec/javascripts/diffs/store/actions_spec.js @@ -161,8 +161,7 @@ describe('DiffsStoreActions', () => { { type: types.SET_LINE_DISCUSSIONS_FOR_FILE, payload: { - diffFile: state.diffFiles[0], - discussions: [singleDiscussion], + discussion: singleDiscussion, diffPositionByLineCode: { ABC_1_1: { baseSha: 'abc', diff --git a/spec/javascripts/diffs/store/mutations_spec.js b/spec/javascripts/diffs/store/mutations_spec.js index 3a9c8f3a825..4b6d3d5bcba 100644 --- a/spec/javascripts/diffs/store/mutations_spec.js +++ b/spec/javascripts/diffs/store/mutations_spec.js @@ -198,40 +198,32 @@ describe('DiffsStoreMutations', () => { }, ], }; - const discussions = [ - { - id: 1, - line_code: 'ABC_1', - diff_discussion: true, - resolvable: true, - original_position: diffPosition, - position: diffPosition, + const discussion = { + id: 1, + line_code: 'ABC_1', + diff_discussion: true, + resolvable: true, + original_position: diffPosition, + position: diffPosition, + diff_file: { + file_hash: state.diffFiles[0].fileHash, }, - { - id: 2, - line_code: 'ABC_1', - diff_discussion: true, - resolvable: true, - original_position: diffPosition, - position: diffPosition, - }, - ]; + }; const diffPositionByLineCode = { ABC_1: diffPosition, }; mutations[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { - diffFile: state.diffFiles[0], - discussions, + discussion, diffPositionByLineCode, }); - expect(state.diffFiles[0].parallelDiffLines[0].left.discussions.length).toEqual(2); - expect(state.diffFiles[0].parallelDiffLines[0].left.discussions[1].id).toEqual(2); + expect(state.diffFiles[0].parallelDiffLines[0].left.discussions.length).toEqual(1); + expect(state.diffFiles[0].parallelDiffLines[0].left.discussions[0].id).toEqual(1); - expect(state.diffFiles[0].highlightedDiffLines[0].discussions.length).toEqual(2); - expect(state.diffFiles[0].highlightedDiffLines[0].discussions[1].id).toEqual(2); + expect(state.diffFiles[0].highlightedDiffLines[0].discussions.length).toEqual(1); + expect(state.diffFiles[0].highlightedDiffLines[0].discussions[0].id).toEqual(1); }); it('should add legacy discussions to the given line', () => { @@ -272,36 +264,30 @@ describe('DiffsStoreMutations', () => { }, ], }; - const discussions = [ - { - id: 1, - line_code: 'ABC_1', - diff_discussion: true, - active: true, + const discussion = { + id: 1, + line_code: 'ABC_1', + diff_discussion: true, + active: true, + diff_file: { + file_hash: state.diffFiles[0].fileHash, }, - { - id: 2, - line_code: 'ABC_1', - diff_discussion: true, - active: true, - }, - ]; + }; const diffPositionByLineCode = { ABC_1: diffPosition, }; mutations[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { - diffFile: state.diffFiles[0], - discussions, + discussion, diffPositionByLineCode, }); - expect(state.diffFiles[0].parallelDiffLines[0].left.discussions.length).toEqual(2); - expect(state.diffFiles[0].parallelDiffLines[0].left.discussions[1].id).toEqual(2); + expect(state.diffFiles[0].parallelDiffLines[0].left.discussions.length).toEqual(1); + expect(state.diffFiles[0].parallelDiffLines[0].left.discussions[0].id).toEqual(1); - expect(state.diffFiles[0].highlightedDiffLines[0].discussions.length).toEqual(2); - expect(state.diffFiles[0].highlightedDiffLines[0].discussions[1].id).toEqual(2); + expect(state.diffFiles[0].highlightedDiffLines[0].discussions.length).toEqual(1); + expect(state.diffFiles[0].highlightedDiffLines[0].discussions[0].id).toEqual(1); }); }); -- cgit v1.2.1