diff options
Diffstat (limited to 'app/assets/javascripts/diffs/store')
7 files changed, 131 insertions, 86 deletions
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index d5581474c9b..0f275f1cb3e 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -52,7 +52,6 @@ export const setBaseConfig = ({ commit }, options) => { projectPath, dismissEndpoint, showSuggestPopover, - useSingleDiffStyle, } = options; commit(types.SET_BASE_CONFIG, { endpoint, @@ -62,61 +61,18 @@ export const setBaseConfig = ({ commit }, options) => { projectPath, dismissEndpoint, showSuggestPopover, - useSingleDiffStyle, }); }; -export const fetchDiffFiles = ({ state, commit }) => { - const worker = new TreeWorker(); - const urlParams = { - w: state.showWhitespace ? '0' : '1', - }; - let returnData; - - if (state.useSingleDiffStyle) { - urlParams.view = state.diffViewType; - } - - commit(types.SET_LOADING, true); - - worker.addEventListener('message', ({ data }) => { - commit(types.SET_TREE_DATA, data); - - worker.terminate(); - }); - - return axios - .get(mergeUrlParams(urlParams, state.endpoint)) - .then(res => { - commit(types.SET_LOADING, false); - - commit(types.SET_MERGE_REQUEST_DIFFS, res.data.merge_request_diffs || []); - commit(types.SET_DIFF_DATA, res.data); - - worker.postMessage(state.diffFiles); - - returnData = res.data; - return Vue.nextTick(); - }) - .then(() => { - handleLocationHash(); - return returnData; - }) - .catch(() => worker.terminate()); -}; - export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => { const id = window?.location?.hash; const isNoteLink = id.indexOf('#note') === 0; const urlParams = { per_page: DIFFS_PER_PAGE, w: state.showWhitespace ? '0' : '1', + view: window.gon?.features?.unifiedDiffLines ? 'inline' : state.diffViewType, }; - if (state.useSingleDiffStyle) { - urlParams.view = state.diffViewType; - } - commit(types.SET_BATCH_LOADING, true); commit(types.SET_RETRIEVING_BATCHES, true); @@ -128,7 +84,7 @@ export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => { commit(types.SET_BATCH_LOADING, false); if (!isNoteLink && !state.currentDiffFileId) { - commit(types.UPDATE_CURRENT_DIFF_FILE_ID, diff_files[0].file_hash); + commit(types.VIEW_DIFF_FILE, diff_files[0].file_hash); } if (isNoteLink) { @@ -144,7 +100,7 @@ export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => { !state.diffFiles.some(f => f.file_hash === state.currentDiffFileId) && !isNoteLink ) { - commit(types.UPDATE_CURRENT_DIFF_FILE_ID, state.diffFiles[0].file_hash); + commit(types.VIEW_DIFF_FILE, state.diffFiles[0].file_hash); } if (gon.features?.codeNavigation) { @@ -175,11 +131,9 @@ export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => { export const fetchDiffFilesMeta = ({ commit, state }) => { const worker = new TreeWorker(); - const urlParams = {}; - - if (state.useSingleDiffStyle) { - urlParams.view = state.diffViewType; - } + const urlParams = { + view: window.gon?.features?.unifiedDiffLines ? 'inline' : state.diffViewType, + }; commit(types.SET_LOADING, true); @@ -229,7 +183,7 @@ export const fetchCoverageFiles = ({ commit, state }) => { export const setHighlightedRow = ({ commit }, lineCode) => { const fileHash = lineCode.split('_')[0]; commit(types.SET_HIGHLIGHTED_ROW, lineCode); - commit(types.UPDATE_CURRENT_DIFF_FILE_ID, fileHash); + commit(types.VIEW_DIFF_FILE, fileHash); }; // This is adding line discussions to the actual lines in the diff tree @@ -240,10 +194,7 @@ export const assignDiscussionsToDiff = ( ) => { const id = window?.location?.hash; const isNoteLink = id.indexOf('#note') === 0; - const diffPositionByLineCode = getDiffPositionByLineCode( - state.diffFiles, - state.useSingleDiffStyle, - ); + const diffPositionByLineCode = getDiffPositionByLineCode(state.diffFiles); const hash = getLocationHash(); discussions @@ -477,13 +428,17 @@ export const toggleTreeOpen = ({ commit }, path) => { commit(types.TOGGLE_FOLDER_OPEN, path); }; +export const toggleActiveFileByHash = ({ commit }, hash) => { + commit(types.VIEW_DIFF_FILE, hash); +}; + export const scrollToFile = ({ state, commit }, path) => { if (!state.treeEntries[path]) return; const { fileHash } = state.treeEntries[path]; document.location.hash = fileHash; - commit(types.UPDATE_CURRENT_DIFF_FILE_ID, fileHash); + commit(types.VIEW_DIFF_FILE, fileHash); }; export const toggleShowTreeList = ({ commit, state }, saving = true) => { @@ -751,7 +706,7 @@ export const setCurrentDiffFileIdFromNote = ({ commit, state, rootGetters }, not const fileHash = rootGetters.getDiscussion(note.discussion_id).diff_file?.file_hash; if (fileHash && state.diffFiles.some(f => f.file_hash === fileHash)) { - commit(types.UPDATE_CURRENT_DIFF_FILE_ID, fileHash); + commit(types.VIEW_DIFF_FILE, fileHash); } }; @@ -759,5 +714,5 @@ export const navigateToDiffFileIndex = ({ commit, state }, index) => { const fileHash = state.diffFiles[index].file_hash; document.location.hash = fileHash; - commit(types.UPDATE_CURRENT_DIFF_FILE_ID, fileHash); + commit(types.VIEW_DIFF_FILE, fileHash); }; diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js index a24894b8d6b..42df5873a41 100644 --- a/app/assets/javascripts/diffs/store/getters.js +++ b/app/assets/javascripts/diffs/store/getters.js @@ -1,4 +1,5 @@ import { __, n__ } from '~/locale'; +import { parallelizeDiffLines } from './utils'; import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '../constants'; export * from './getters_versions_dropdowns'; @@ -129,3 +130,11 @@ export const fileLineCoverage = state => (file, line) => { */ export const currentDiffIndex = state => Math.max(0, state.diffFiles.findIndex(diff => diff.file_hash === state.currentDiffFileId)); + +export const diffLines = state => file => { + if (state.diffViewType === INLINE_DIFF_VIEW_TYPE) { + return null; + } + + return parallelizeDiffLines(file.highlighted_diff_lines || []); +}; diff --git a/app/assets/javascripts/diffs/store/getters_versions_dropdowns.js b/app/assets/javascripts/diffs/store/getters_versions_dropdowns.js index 1e8e736c028..135b1c61ef5 100644 --- a/app/assets/javascripts/diffs/store/getters_versions_dropdowns.js +++ b/app/assets/javascripts/diffs/store/getters_versions_dropdowns.js @@ -11,17 +11,26 @@ export const diffCompareDropdownTargetVersions = (state, getters) => { // startVersion only exists if the user has selected a version other // than "base" so if startVersion is null then base must be selected - const diffHead = parseBoolean(getParameterByName('diff_head')); + const defaultMergeRefForDiffs = window.gon?.features?.defaultMergeRefForDiffs || false; + const diffHeadParam = getParameterByName('diff_head'); + const diffHead = parseBoolean(diffHeadParam) || (!diffHeadParam && defaultMergeRefForDiffs); const isBaseSelected = !state.startVersion && !diffHead; const isHeadSelected = !state.startVersion && diffHead; + let baseVersion = null; - const baseVersion = { - versionName: state.targetBranchName, - version_index: DIFF_COMPARE_BASE_VERSION_INDEX, - href: state.mergeRequestDiff.base_version_path, - isBase: true, - selected: isBaseSelected, - }; + if ( + !defaultMergeRefForDiffs || + (defaultMergeRefForDiffs && !state.mergeRequestDiff.head_version_path) + ) { + baseVersion = { + versionName: state.targetBranchName, + version_index: DIFF_COMPARE_BASE_VERSION_INDEX, + href: state.mergeRequestDiff.base_version_path, + isBase: true, + selected: + isBaseSelected || (defaultMergeRefForDiffs && !state.mergeRequestDiff.head_version_path), + }; + } const headVersion = { versionName: state.targetBranchName, @@ -40,7 +49,11 @@ export const diffCompareDropdownTargetVersions = (state, getters) => { }; }; - return [...state.mergeRequestDiffs.slice(1).map(formatVersion), baseVersion, headVersion]; + return [ + ...state.mergeRequestDiffs.slice(1).map(formatVersion), + baseVersion, + state.mergeRequestDiff.head_version_path && headVersion, + ].filter(a => a); }; export const diffCompareDropdownSourceVersions = (state, getters) => { diff --git a/app/assets/javascripts/diffs/store/modules/diff_state.js b/app/assets/javascripts/diffs/store/modules/diff_state.js index d31a600e354..001d9d9f594 100644 --- a/app/assets/javascripts/diffs/store/modules/diff_state.js +++ b/app/assets/javascripts/diffs/store/modules/diff_state.js @@ -34,6 +34,7 @@ export default () => ({ showTreeList: true, currentDiffFileId: '', projectPath: '', + viewedDiffFileIds: {}, commentForms: [], highlightedRow: null, renderTreeList: true, @@ -41,5 +42,4 @@ export default () => ({ fileFinderVisible: false, dismissEndpoint: '', showSuggestPopover: true, - useSingleDiffStyle: false, }); diff --git a/app/assets/javascripts/diffs/store/mutation_types.js b/app/assets/javascripts/diffs/store/mutation_types.js index 4b1dbc34902..5dba2e9d10d 100644 --- a/app/assets/javascripts/diffs/store/mutation_types.js +++ b/app/assets/javascripts/diffs/store/mutation_types.js @@ -19,7 +19,7 @@ export const SET_LINE_DISCUSSIONS_FOR_FILE = 'SET_LINE_DISCUSSIONS_FOR_FILE'; export const REMOVE_LINE_DISCUSSIONS_FOR_FILE = 'REMOVE_LINE_DISCUSSIONS_FOR_FILE'; export const TOGGLE_FOLDER_OPEN = 'TOGGLE_FOLDER_OPEN'; export const TOGGLE_SHOW_TREE_LIST = 'TOGGLE_SHOW_TREE_LIST'; -export const UPDATE_CURRENT_DIFF_FILE_ID = 'UPDATE_CURRENT_DIFF_FILE_ID'; +export const VIEW_DIFF_FILE = 'VIEW_DIFF_FILE'; export const OPEN_DIFF_FILE_COMMENT_FORM = 'OPEN_DIFF_FILE_COMMENT_FORM'; export const UPDATE_DIFF_FILE_COMMENT_FORM = 'UPDATE_DIFF_FILE_COMMENT_FORM'; diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index 0d41f1c2178..7925c620c4e 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -1,4 +1,6 @@ +import Vue from 'vue'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; +import { INLINE_DIFF_VIEW_TYPE } from '../constants'; import { findDiffFile, addLineReferences, @@ -24,7 +26,6 @@ export default { projectPath, dismissEndpoint, showSuggestPopover, - useSingleDiffStyle, } = options; Object.assign(state, { endpoint, @@ -34,7 +35,6 @@ export default { projectPath, dismissEndpoint, showSuggestPopover, - useSingleDiffStyle, }); }, @@ -57,10 +57,7 @@ export default { [types.SET_DIFF_DATA](state, data) { let files = state.diffFiles; - if ( - !(gon?.features?.diffsBatchLoad && window.location.search.indexOf('diff_id') === -1) && - data.diff_files - ) { + if (window.location.search.indexOf('diff_id') !== -1 && data.diff_files) { files = prepareDiffData(data, files); } @@ -154,7 +151,9 @@ export default { addContextLines({ inlineLines: diffFile.highlighted_diff_lines, parallelLines: diffFile.parallel_diff_lines, - diffViewType: state.diffViewType, + diffViewType: window.gon?.features?.unifiedDiffLines + ? INLINE_DIFF_VIEW_TYPE + : state.diffViewType, contextLines: lines, bottom, lineNumbers, @@ -249,7 +248,7 @@ export default { }); } - if (!file.parallel_diff_lines || !file.highlighted_diff_lines) { + if (!file.parallel_diff_lines.length || !file.highlighted_diff_lines.length) { const newDiscussions = (file.discussions || []) .filter(d => d.id !== discussion.id) .concat(discussion); @@ -293,8 +292,9 @@ export default { [types.TOGGLE_SHOW_TREE_LIST](state) { state.showTreeList = !state.showTreeList; }, - [types.UPDATE_CURRENT_DIFF_FILE_ID](state, fileId) { + [types.VIEW_DIFF_FILE](state, fileId) { state.currentDiffFileId = fileId; + Vue.set(state.viewedDiffFileIds, fileId, true); }, [types.OPEN_DIFF_FILE_COMMENT_FORM](state, formData) { state.commentForms.push({ diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js index f014cddda32..69330ffae2f 100644 --- a/app/assets/javascripts/diffs/store/utils.js +++ b/app/assets/javascripts/diffs/store/utils.js @@ -11,7 +11,6 @@ import { OLD_LINE_TYPE, MATCH_LINE_TYPE, LINES_TO_BE_RENDERED_DIRECTLY, - MAX_LINES_TO_BE_RENDERED, TREE_TYPE, INLINE_DIFF_VIEW_TYPE, PARALLEL_DIFF_VIEW_TYPE, @@ -20,6 +19,77 @@ import { } from '../constants'; import { prepareRawDiffFile } from '../diff_file'; +export const isAdded = line => ['new', 'new-nonewline'].includes(line.type); +export const isRemoved = line => ['old', 'old-nonewline'].includes(line.type); +export const isUnchanged = line => !line.type; +export const isMeta = line => ['match', 'new-nonewline', 'old-nonewline'].includes(line.type); + +/** + * Pass in the inline diff lines array which gets converted + * to the parallel diff lines. + * This allows for us to convert inline diff lines to parallel + * on the frontend without needing to send any requests + * to the API. + * + * This method has been taken from the already existing backend + * implementation at lib/gitlab/diff/parallel_diff.rb + * + * @param {Object[]} diffLines - inline diff lines + * + * @returns {Object[]} parallel lines + */ +export const parallelizeDiffLines = (diffLines = []) => { + let freeRightIndex = null; + const lines = []; + + for (let i = 0, diffLinesLength = diffLines.length, index = 0; i < diffLinesLength; i += 1) { + const line = diffLines[i]; + + if (isRemoved(line)) { + lines.push({ + [LINE_POSITION_LEFT]: line, + [LINE_POSITION_RIGHT]: null, + }); + + if (freeRightIndex === null) { + // Once we come upon a new line it can be put on the right of this old line + freeRightIndex = index; + } + index += 1; + } else if (isAdded(line)) { + if (freeRightIndex !== null) { + // If an old line came before this without a line on the right, this + // line can be put to the right of it. + lines[freeRightIndex].right = line; + + // If there are any other old lines on the left that don't yet have + // a new counterpart on the right, update the free_right_index + const nextFreeRightIndex = freeRightIndex + 1; + freeRightIndex = nextFreeRightIndex < index ? nextFreeRightIndex : null; + } else { + lines.push({ + [LINE_POSITION_LEFT]: null, + [LINE_POSITION_RIGHT]: line, + }); + + freeRightIndex = null; + index += 1; + } + } else if (isMeta(line) || isUnchanged(line)) { + // line in the right panel is the same as in the left one + lines.push({ + [LINE_POSITION_LEFT]: line, + [LINE_POSITION_RIGHT]: line, + }); + + freeRightIndex = null; + index += 1; + } + } + + return lines; +}; + export function findDiffFile(files, match, matchKey = 'file_hash') { return files.find(file => file[matchKey] === match); } @@ -281,7 +351,7 @@ function mergeTwoFiles(target, source) { function ensureBasicDiffFileLines(file) { const missingInline = !file.highlighted_diff_lines; - const missingParallel = !file.parallel_diff_lines; + const missingParallel = !file.parallel_diff_lines || window.gon?.features?.unifiedDiffLines; Object.assign(file, { highlighted_diff_lines: missingInline ? [] : file.highlighted_diff_lines, @@ -379,12 +449,10 @@ function getVisibleDiffLines(file) { } function finalizeDiffFile(file) { - const name = (file.viewer && file.viewer.name) || diffViewerModes.text; const lines = getVisibleDiffLines(file); Object.assign(file, { renderIt: lines < LINES_TO_BE_RENDERED_DIRECTLY, - collapsed: name === diffViewerModes.text && lines > MAX_LINES_TO_BE_RENDERED, isShowingFullFile: false, isLoadingFullFile: false, discussions: [], @@ -417,11 +485,11 @@ export function prepareDiffData(diff, priorFiles = []) { return deduplicateFilesList([...priorFiles, ...cleanedFiles]); } -export function getDiffPositionByLineCode(diffFiles, useSingleDiffStyle) { +export function getDiffPositionByLineCode(diffFiles) { let lines = []; const hasInlineDiffs = diffFiles.some(file => file.highlighted_diff_lines.length > 0); - if (!useSingleDiffStyle || hasInlineDiffs) { + if (hasInlineDiffs) { // In either of these cases, we can use `highlighted_diff_lines` because // that will include all of the parallel diff lines, too |