debian-mirror-gitlab/app/assets/javascripts/diffs/store/actions.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

864 lines
25 KiB
JavaScript
Raw Normal View History

2021-03-11 19:13:27 +05:30
import Vue from 'vue';
2022-04-04 11:22:00 +05:30
import {
setCookie,
handleLocationHash,
historyPushState,
scrollToElement,
} from '~/lib/utils/common_utils';
2021-09-04 01:27:46 +05:30
import createFlash from '~/flash';
2021-03-11 19:13:27 +05:30
import { diffViewerModes } from '~/ide/constants';
import axios from '~/lib/utils/axios_utils';
2022-04-04 11:22:00 +05:30
2021-03-11 19:13:27 +05:30
import httpStatusCodes from '~/lib/utils/http_status';
import Poll from '~/lib/utils/poll';
2018-11-20 20:47:30 +05:30
import { mergeUrlParams, getLocationHash } from '~/lib/utils/url_utility';
2021-03-11 19:13:27 +05:30
import { __, s__ } from '~/locale';
2022-06-21 17:19:12 +05:30
import notesEventHub from '~/notes/event_hub';
2018-11-08 19:23:39 +05:30
import {
PARALLEL_DIFF_VIEW_TYPE,
INLINE_DIFF_VIEW_TYPE,
DIFF_VIEW_COOKIE_NAME,
2018-12-05 23:21:45 +05:30
MR_TREE_SHOW_KEY,
2019-03-02 22:35:43 +05:30
TREE_LIST_STORAGE_KEY,
2019-07-07 11:18:12 +05:30
TREE_LIST_WIDTH_STORAGE_KEY,
2019-07-31 22:56:46 +05:30
OLD_LINE_KEY,
NEW_LINE_KEY,
TYPE_KEY,
MAX_RENDERING_DIFF_LINES,
MAX_RENDERING_BULK_ROWS,
MIN_RENDERING_MS,
START_RENDERING_INDEX,
INLINE_DIFF_LINES_KEY,
2021-01-29 00:20:46 +05:30
DIFF_FILE_MANUAL_COLLAPSE,
DIFF_FILE_AUTOMATIC_COLLAPSE,
EVT_PERF_MARK_FILE_TREE_START,
EVT_PERF_MARK_FILE_TREE_END,
EVT_PERF_MARK_DIFF_FILES_START,
2021-06-08 01:23:25 +05:30
TRACKING_CLICK_DIFF_VIEW_SETTING,
TRACKING_DIFF_VIEW_INLINE,
TRACKING_DIFF_VIEW_PARALLEL,
TRACKING_CLICK_FILE_BROWSER_SETTING,
TRACKING_FILE_BROWSER_TREE,
TRACKING_FILE_BROWSER_LIST,
TRACKING_CLICK_WHITESPACE_SETTING,
TRACKING_WHITESPACE_SHOW,
TRACKING_WHITESPACE_HIDE,
TRACKING_CLICK_SINGLE_FILE_SETTING,
TRACKING_SINGLE_FILE_MODE,
TRACKING_MULTIPLE_FILES_MODE,
2018-11-08 19:23:39 +05:30
} from '../constants';
2021-03-11 19:13:27 +05:30
import eventHub from '../event_hub';
2021-02-22 17:27:13 +05:30
import { isCollapsed } from '../utils/diff_file';
2021-03-08 18:12:59 +05:30
import { markFileReview, setReviewsForMergeRequest } from '../utils/file_reviews';
2021-03-11 19:13:27 +05:30
import { getDerivedMergeRequestInformation } from '../utils/merge_request';
2021-10-27 15:23:28 +05:30
import { queueRedisHllEvents } from '../utils/queue_events';
2021-03-11 19:13:27 +05:30
import TreeWorker from '../workers/tree_worker';
import * as types from './mutation_types';
import {
getDiffPositionByLineCode,
getNoteFormData,
convertExpandLines,
idleCallback,
allDiscussionWrappersExpanded,
prepareLineForRenamedFile,
} from './utils';
2018-11-08 19:23:39 +05:30
export const setBaseConfig = ({ commit }, options) => {
2020-01-01 13:55:28 +05:30
const {
endpoint,
endpointMetadata,
endpointBatch,
2020-04-08 14:13:33 +05:30
endpointCoverage,
2021-04-29 21:17:54 +05:30
endpointUpdateUser,
2020-01-01 13:55:28 +05:30
projectPath,
dismissEndpoint,
showSuggestPopover,
2021-03-08 18:12:59 +05:30
defaultSuggestionCommitMessage,
2021-02-22 17:27:13 +05:30
viewDiffsFileByFile,
2021-03-08 18:12:59 +05:30
mrReviews,
2020-01-01 13:55:28 +05:30
} = options;
commit(types.SET_BASE_CONFIG, {
endpoint,
endpointMetadata,
endpointBatch,
2020-04-08 14:13:33 +05:30
endpointCoverage,
2021-04-29 21:17:54 +05:30
endpointUpdateUser,
2020-01-01 13:55:28 +05:30
projectPath,
dismissEndpoint,
showSuggestPopover,
2021-03-08 18:12:59 +05:30
defaultSuggestionCommitMessage,
2021-02-22 17:27:13 +05:30
viewDiffsFileByFile,
2021-03-08 18:12:59 +05:30
mrReviews,
2020-01-01 13:55:28 +05:30
});
2021-12-11 22:18:48 +05:30
Array.from(new Set(Object.values(mrReviews).flat())).forEach((id) => {
const viewedId = id.replace(/^hash:/, '');
commit(types.SET_DIFF_FILE_VIEWED, { id: viewedId, seen: true });
});
2018-11-08 19:23:39 +05:30
};
2020-07-28 23:09:34 +05:30
export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => {
2021-09-30 23:02:18 +05:30
let perPage = state.viewDiffsFileByFile ? 1 : 5;
2021-02-22 17:27:13 +05:30
let increaseAmount = 1.4;
2021-09-30 23:02:18 +05:30
const startPage = 0;
2020-07-28 23:09:34 +05:30
const id = window?.location?.hash;
const isNoteLink = id.indexOf('#note') === 0;
2020-03-13 15:44:24 +05:30
const urlParams = {
w: state.showWhitespace ? '0' : '1',
2021-02-22 17:27:13 +05:30
view: 'inline',
2020-03-13 15:44:24 +05:30
};
2021-09-30 23:02:18 +05:30
const hash = window.location.hash.replace('#', '').split('diff-content-').pop();
2021-02-22 17:27:13 +05:30
let totalLoaded = 0;
2021-09-30 23:02:18 +05:30
let scrolledVirtualScroller = false;
2020-03-13 15:44:24 +05:30
2021-11-11 11:23:49 +05:30
commit(types.SET_BATCH_LOADING_STATE, 'loading');
2020-03-13 15:44:24 +05:30
commit(types.SET_RETRIEVING_BATCHES, true);
2021-01-29 00:20:46 +05:30
eventHub.$emit(EVT_PERF_MARK_DIFF_FILES_START);
2020-01-01 13:55:28 +05:30
2021-02-22 17:27:13 +05:30
const getBatch = (page = startPage) =>
2020-01-01 13:55:28 +05:30
axios
2021-02-22 17:27:13 +05:30
.get(mergeUrlParams({ ...urlParams, page, per_page: perPage }, state.endpointBatch))
2022-08-27 11:52:29 +05:30
.then(({ data: { pagination, diff_files: diffFiles } }) => {
totalLoaded += diffFiles.length;
2021-02-22 17:27:13 +05:30
2022-08-27 11:52:29 +05:30
commit(types.SET_DIFF_DATA_BATCH, { diff_files: diffFiles });
2021-11-11 11:23:49 +05:30
commit(types.SET_BATCH_LOADING_STATE, 'loaded');
2020-03-13 15:44:24 +05:30
2022-04-04 11:22:00 +05:30
if (!scrolledVirtualScroller) {
2021-09-30 23:02:18 +05:30
const index = state.diffFiles.findIndex(
(f) =>
f.file_hash === hash || f[INLINE_DIFF_LINES_KEY].find((l) => l.line_code === hash),
);
if (index >= 0) {
eventHub.$emit('scrollToIndex', index);
scrolledVirtualScroller = true;
}
}
2020-07-28 23:09:34 +05:30
if (!isNoteLink && !state.currentDiffFileId) {
2022-08-27 11:52:29 +05:30
commit(types.SET_CURRENT_DIFF_FILE, diffFiles[0]?.file_hash);
2020-07-28 23:09:34 +05:30
}
if (isNoteLink) {
dispatch('setCurrentDiffFileIdFromNote', id.split('_').pop());
}
2021-09-30 23:02:18 +05:30
if (totalLoaded === pagination.total_pages || pagination.total_pages === null) {
2020-03-13 15:44:24 +05:30
commit(types.SET_RETRIEVING_BATCHES, false);
2020-07-28 23:09:34 +05:30
// We need to check that the currentDiffFileId points to a file that exists
if (
state.currentDiffFileId &&
2021-03-08 18:12:59 +05:30
!state.diffFiles.some((f) => f.file_hash === state.currentDiffFileId) &&
2020-07-28 23:09:34 +05:30
!isNoteLink
) {
2021-12-11 22:18:48 +05:30
commit(types.SET_CURRENT_DIFF_FILE, state.diffFiles[0].file_hash);
2020-07-28 23:09:34 +05:30
}
2021-01-03 14:25:43 +05:30
if (state.diffFiles?.length) {
2020-04-22 19:07:51 +05:30
// eslint-disable-next-line promise/catch-or-return,promise/no-nesting
2021-03-08 18:12:59 +05:30
import('~/code_navigation').then((m) =>
2020-04-22 19:07:51 +05:30
m.default({
2020-07-28 23:09:34 +05:30
blobs: state.diffFiles
2021-03-08 18:12:59 +05:30
.filter((f) => f.code_navigation_path)
.map((f) => ({
2020-07-28 23:09:34 +05:30
path: f.new_path,
codeNavigationPath: f.code_navigation_path,
})),
2020-04-22 19:07:51 +05:30
definitionPathPrefix: state.definitionPathPrefix,
}),
);
}
2021-02-22 17:27:13 +05:30
return null;
}
2021-09-30 23:02:18 +05:30
const nextPage = page + perPage;
perPage = Math.min(Math.ceil(perPage * increaseAmount), 30);
increaseAmount = Math.min(increaseAmount + 0.2, 2);
2021-02-22 17:27:13 +05:30
2021-09-30 23:02:18 +05:30
return nextPage;
2020-01-01 13:55:28 +05:30
})
2021-04-29 21:17:54 +05:30
.then((nextPage) => {
dispatch('startRenderDiffsQueue');
if (nextPage) {
return getBatch(nextPage);
}
return null;
})
2021-11-11 11:23:49 +05:30
.catch(() => {
commit(types.SET_RETRIEVING_BATCHES, false);
commit(types.SET_BATCH_LOADING_STATE, 'error');
});
2020-01-01 13:55:28 +05:30
2022-04-04 11:22:00 +05:30
return getBatch();
2020-01-01 13:55:28 +05:30
};
export const fetchDiffFilesMeta = ({ commit, state }) => {
const worker = new TreeWorker();
2020-11-24 15:15:51 +05:30
const urlParams = {
2021-02-22 17:27:13 +05:30
view: 'inline',
2020-11-24 15:15:51 +05:30
};
2020-01-01 13:55:28 +05:30
commit(types.SET_LOADING, true);
2021-01-29 00:20:46 +05:30
eventHub.$emit(EVT_PERF_MARK_FILE_TREE_START);
2020-01-01 13:55:28 +05:30
worker.addEventListener('message', ({ data }) => {
commit(types.SET_TREE_DATA, data);
2021-01-29 00:20:46 +05:30
eventHub.$emit(EVT_PERF_MARK_FILE_TREE_END);
2020-01-01 13:55:28 +05:30
worker.terminate();
});
return axios
2020-03-13 15:44:24 +05:30
.get(mergeUrlParams(urlParams, state.endpointMetadata))
2020-01-01 13:55:28 +05:30
.then(({ data }) => {
const strippedData = { ...data };
delete strippedData.diff_files;
2021-02-22 17:27:13 +05:30
2020-01-01 13:55:28 +05:30
commit(types.SET_LOADING, false);
commit(types.SET_MERGE_REQUEST_DIFFS, data.merge_request_diffs || []);
2021-02-22 17:27:13 +05:30
commit(types.SET_DIFF_METADATA, strippedData);
2020-01-01 13:55:28 +05:30
2021-04-29 21:17:54 +05:30
worker.postMessage(data.diff_files);
2020-03-13 15:44:24 +05:30
return data;
2020-01-01 13:55:28 +05:30
})
.catch(() => worker.terminate());
};
2020-04-08 14:13:33 +05:30
export const fetchCoverageFiles = ({ commit, state }) => {
const coveragePoll = new Poll({
resource: {
2021-03-08 18:12:59 +05:30
getCoverageReports: (endpoint) => axios.get(endpoint),
2020-04-08 14:13:33 +05:30
},
data: state.endpointCoverage,
method: 'getCoverageReports',
successCallback: ({ status, data }) => {
if (status === httpStatusCodes.OK) {
commit(types.SET_COVERAGE_DATA, data);
coveragePoll.stop();
}
},
2021-09-04 01:27:46 +05:30
errorCallback: () =>
createFlash({
message: __('Something went wrong on our end. Please try again!'),
}),
2020-04-08 14:13:33 +05:30
});
coveragePoll.makeRequest();
};
2019-02-15 15:39:39 +05:30
export const setHighlightedRow = ({ commit }, lineCode) => {
2019-07-07 11:18:12 +05:30
const fileHash = lineCode.split('_')[0];
2019-02-15 15:39:39 +05:30
commit(types.SET_HIGHLIGHTED_ROW, lineCode);
2021-12-11 22:18:48 +05:30
commit(types.SET_CURRENT_DIFF_FILE, fileHash);
2021-09-30 23:02:18 +05:30
handleLocationHash();
2019-02-15 15:39:39 +05:30
};
2018-11-20 20:47:30 +05:30
// This is adding line discussions to the actual lines in the diff tree
// once for parallel and once for inline mode
2018-12-13 13:39:08 +05:30
export const assignDiscussionsToDiff = (
2020-07-28 23:09:34 +05:30
{ commit, state, rootState, dispatch },
2018-12-13 13:39:08 +05:30
discussions = rootState.notes.discussions,
) => {
2020-07-28 23:09:34 +05:30
const id = window?.location?.hash;
const isNoteLink = id.indexOf('#note') === 0;
2020-11-24 15:15:51 +05:30
const diffPositionByLineCode = getDiffPositionByLineCode(state.diffFiles);
2019-09-30 21:07:59 +05:30
const hash = getLocationHash();
2018-11-20 20:47:30 +05:30
2019-02-15 15:39:39 +05:30
discussions
2021-03-08 18:12:59 +05:30
.filter((discussion) => discussion.diff_discussion)
.forEach((discussion) => {
2019-02-15 15:39:39 +05:30
commit(types.SET_LINE_DISCUSSIONS_FOR_FILE, {
discussion,
diffPositionByLineCode,
2019-09-30 21:07:59 +05:30
hash,
2019-02-15 15:39:39 +05:30
});
2018-12-13 13:39:08 +05:30
});
2019-02-15 15:39:39 +05:30
2020-07-28 23:09:34 +05:30
if (isNoteLink) {
dispatch('setCurrentDiffFileIdFromNote', id.split('_').pop());
}
2019-02-15 15:39:39 +05:30
Vue.nextTick(() => {
2021-01-29 00:20:46 +05:30
notesEventHub.$emit('scrollToDiscussion');
2018-11-20 20:47:30 +05:30
});
};
export const removeDiscussionsFromDiff = ({ commit }, removeDiscussion) => {
2022-08-27 11:52:29 +05:30
const { file_hash: fileHash, line_code: lineCode, id } = removeDiscussion;
commit(types.REMOVE_LINE_DISCUSSIONS_FOR_FILE, { fileHash, lineCode, id });
2019-02-15 15:39:39 +05:30
};
2019-09-30 21:07:59 +05:30
export const toggleLineDiscussions = ({ commit }, options) => {
commit(types.TOGGLE_LINE_DISCUSSIONS, options);
};
2019-02-15 15:39:39 +05:30
export const renderFileForDiscussionId = ({ commit, rootState, state }, discussionId) => {
2021-03-08 18:12:59 +05:30
const discussion = rootState.notes.discussions.find((d) => d.id === discussionId);
2019-02-15 15:39:39 +05:30
2019-10-12 21:52:04 +05:30
if (discussion && discussion.diff_file) {
2021-03-08 18:12:59 +05:30
const file = state.diffFiles.find((f) => f.file_hash === discussion.diff_file.file_hash);
2019-02-15 15:39:39 +05:30
if (file) {
if (!file.renderIt) {
commit(types.RENDER_FILE, file);
}
2021-01-03 14:25:43 +05:30
if (file.viewer.automaticallyCollapsed) {
2021-01-29 00:20:46 +05:30
notesEventHub.$emit(`loadCollapsedDiff/${file.file_hash}`);
2019-02-15 15:39:39 +05:30
scrollToElement(document.getElementById(file.file_hash));
2021-01-29 00:20:46 +05:30
} else if (file.viewer.manuallyCollapsed) {
commit(types.SET_FILE_COLLAPSED, {
filePath: file.file_path,
collapsed: false,
trigger: DIFF_FILE_AUTOMATIC_COLLAPSE,
});
notesEventHub.$emit('scrollToDiscussion');
2019-02-15 15:39:39 +05:30
} else {
2021-01-29 00:20:46 +05:30
notesEventHub.$emit('scrollToDiscussion');
2019-02-15 15:39:39 +05:30
}
}
}
2018-11-20 20:47:30 +05:30
};
export const startRenderDiffsQueue = ({ state, commit }) => {
2021-04-29 21:17:54 +05:30
const diffFilesToRender = state.diffFiles.filter(
(file) =>
!file.renderIt &&
file.viewer &&
(!isCollapsed(file) || file.viewer.name !== diffViewerModes.text),
);
let currentDiffFileIndex = 0;
const checkItem = () => {
const nextFile = diffFilesToRender[currentDiffFileIndex];
if (nextFile) {
let retryCount = 0;
currentDiffFileIndex += 1;
commit(types.RENDER_FILE, nextFile);
const requestIdle = () =>
requestIdleCallback((idleDeadline) => {
// Wait for at least 5ms before trying to render
// or for 5 tries and then force render the file
if (idleDeadline.timeRemaining() >= 5 || retryCount > 4) {
checkItem();
} else {
requestIdle();
retryCount += 1;
}
2018-11-20 20:47:30 +05:30
});
2021-04-29 21:17:54 +05:30
requestIdle();
}
};
if (diffFilesToRender.length) {
checkItem();
}
2018-11-20 20:47:30 +05:30
};
2019-07-07 11:18:12 +05:30
export const setRenderIt = ({ commit }, file) => commit(types.RENDER_FILE, file);
2018-11-08 19:23:39 +05:30
export const setInlineDiffViewType = ({ commit }) => {
commit(types.SET_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE);
2022-04-04 11:22:00 +05:30
setCookie(DIFF_VIEW_COOKIE_NAME, INLINE_DIFF_VIEW_TYPE);
2018-11-08 19:23:39 +05:30
const url = mergeUrlParams({ view: INLINE_DIFF_VIEW_TYPE }, window.location.href);
historyPushState(url);
2021-06-08 01:23:25 +05:30
2022-06-21 17:19:12 +05:30
queueRedisHllEvents([TRACKING_CLICK_DIFF_VIEW_SETTING, TRACKING_DIFF_VIEW_INLINE]);
2018-11-08 19:23:39 +05:30
};
export const setParallelDiffViewType = ({ commit }) => {
commit(types.SET_DIFF_VIEW_TYPE, PARALLEL_DIFF_VIEW_TYPE);
2022-04-04 11:22:00 +05:30
setCookie(DIFF_VIEW_COOKIE_NAME, PARALLEL_DIFF_VIEW_TYPE);
2018-11-08 19:23:39 +05:30
const url = mergeUrlParams({ view: PARALLEL_DIFF_VIEW_TYPE }, window.location.href);
historyPushState(url);
2021-06-08 01:23:25 +05:30
2022-06-21 17:19:12 +05:30
queueRedisHllEvents([TRACKING_CLICK_DIFF_VIEW_SETTING, TRACKING_DIFF_VIEW_PARALLEL]);
2018-11-08 19:23:39 +05:30
};
2019-02-15 15:39:39 +05:30
export const showCommentForm = ({ commit }, { lineCode, fileHash }) => {
commit(types.TOGGLE_LINE_HAS_FORM, { lineCode, fileHash, hasForm: true });
2018-11-08 19:23:39 +05:30
};
2019-02-15 15:39:39 +05:30
export const cancelCommentForm = ({ commit }, { lineCode, fileHash }) => {
commit(types.TOGGLE_LINE_HAS_FORM, { lineCode, fileHash, hasForm: false });
2018-11-08 19:23:39 +05:30
};
export const loadMoreLines = ({ commit }, options) => {
2019-10-12 21:52:04 +05:30
const { endpoint, params, lineNumbers, fileHash, isExpandDown, nextLineNumbers } = options;
2018-11-08 19:23:39 +05:30
params.from_merge_request = true;
2021-03-08 18:12:59 +05:30
return axios.get(endpoint, { params }).then((res) => {
2018-11-08 19:23:39 +05:30
const contextLines = res.data || [];
commit(types.ADD_CONTEXT_LINES, {
lineNumbers,
contextLines,
params,
fileHash,
2019-10-12 21:52:04 +05:30
isExpandDown,
nextLineNumbers,
2018-11-08 19:23:39 +05:30
});
});
};
2018-11-20 20:47:30 +05:30
export const scrollToLineIfNeededInline = (_, line) => {
const hash = getLocationHash();
2019-02-15 15:39:39 +05:30
if (hash && line.line_code === hash) {
2018-11-20 20:47:30 +05:30
handleLocationHash();
}
};
export const scrollToLineIfNeededParallel = (_, line) => {
const hash = getLocationHash();
if (
hash &&
2019-02-15 15:39:39 +05:30
((line.left && line.left.line_code === hash) || (line.right && line.right.line_code === hash))
2018-11-20 20:47:30 +05:30
) {
handleLocationHash();
}
};
2019-09-04 21:01:54 +05:30
export const loadCollapsedDiff = ({ commit, getters, state }, file) =>
2019-02-15 15:39:39 +05:30
axios
.get(file.load_collapsed_diff_url, {
params: {
commit_id: getters.commitId,
2019-09-04 21:01:54 +05:30
w: state.showWhitespace ? '0' : '1',
2019-02-15 15:39:39 +05:30
},
})
2021-03-08 18:12:59 +05:30
.then((res) => {
2019-02-15 15:39:39 +05:30
commit(types.ADD_COLLAPSED_DIFFS, {
file,
data: res.data,
});
2018-11-08 19:23:39 +05:30
});
/**
* Toggles the file discussions after user clicked on the toggle discussions button.
*
* Gets the discussions for the provided diff.
*
* If all discussions are expanded, it will collapse all of them
* If all discussions are collapsed, it will expand all of them
* If some discussions are open and others closed, it will expand the closed ones.
*
* @param {Object} diff
*/
export const toggleFileDiscussions = ({ getters, dispatch }, diff) => {
const discussions = getters.getDiffFileDiscussions(diff);
const shouldCloseAll = getters.diffHasAllExpandedDiscussions(diff);
2019-02-15 15:39:39 +05:30
const shouldExpandAll = getters.diffHasAllCollapsedDiscussions(diff);
2018-11-08 19:23:39 +05:30
2021-03-08 18:12:59 +05:30
discussions.forEach((discussion) => {
2018-11-08 19:23:39 +05:30
const data = { discussionId: discussion.id };
if (shouldCloseAll) {
dispatch('collapseDiscussion', data, { root: true });
} else if (shouldExpandAll || (!shouldCloseAll && !shouldExpandAll && !discussion.expanded)) {
dispatch('expandDiscussion', data, { root: true });
}
});
};
2019-09-30 21:07:59 +05:30
export const toggleFileDiscussionWrappers = ({ commit }, diff) => {
const discussionWrappersExpanded = allDiscussionWrappersExpanded(diff);
2020-03-13 15:44:24 +05:30
const lineCodesWithDiscussions = new Set();
2021-03-08 18:12:59 +05:30
const lineHasDiscussion = (line) => Boolean(line?.discussions.length);
const registerDiscussionLine = (line) => lineCodesWithDiscussions.add(line.line_code);
2020-03-13 15:44:24 +05:30
2021-02-22 17:27:13 +05:30
diff[INLINE_DIFF_LINES_KEY].filter(lineHasDiscussion).forEach(registerDiscussionLine);
2020-03-13 15:44:24 +05:30
if (lineCodesWithDiscussions.size) {
2021-03-08 18:12:59 +05:30
Array.from(lineCodesWithDiscussions).forEach((lineCode) => {
2019-09-30 21:07:59 +05:30
commit(types.TOGGLE_LINE_DISCUSSIONS, {
fileHash: diff.file_hash,
expanded: !discussionWrappersExpanded,
2020-03-13 15:44:24 +05:30
lineCode,
2019-09-30 21:07:59 +05:30
});
});
}
};
2019-02-15 15:39:39 +05:30
export const saveDiffDiscussion = ({ state, dispatch }, { note, formData }) => {
2018-12-05 23:21:45 +05:30
const postData = getNoteFormData({
2019-02-15 15:39:39 +05:30
commit: state.commit,
2018-12-05 23:21:45 +05:30
note,
...formData,
});
return dispatch('saveNote', postData, { root: true })
2021-03-08 18:12:59 +05:30
.then((result) => dispatch('updateDiscussion', result.discussion, { root: true }))
.then((discussion) => dispatch('assignDiscussionsToDiff', [discussion]))
2019-09-30 21:07:59 +05:30
.then(() => dispatch('updateResolvableDiscussionsCounts', null, { root: true }))
2019-02-15 15:39:39 +05:30
.then(() => dispatch('closeDiffFileCommentForm', formData.diffFile.file_hash))
2021-09-04 01:27:46 +05:30
.catch(() =>
createFlash({
message: s__('MergeRequests|Saving the comment failed'),
}),
);
2018-12-05 23:21:45 +05:30
};
export const toggleTreeOpen = ({ commit }, path) => {
commit(types.TOGGLE_FOLDER_OPEN, path);
};
2021-12-11 22:18:48 +05:30
export const setCurrentFileHash = ({ commit }, hash) => {
commit(types.SET_CURRENT_DIFF_FILE, hash);
2020-11-24 15:15:51 +05:30
};
2022-04-04 11:22:00 +05:30
export const scrollToFile = ({ state, commit, getters }, { path }) => {
2020-07-28 23:09:34 +05:30
if (!state.treeEntries[path]) return;
2018-12-05 23:21:45 +05:30
const { fileHash } = state.treeEntries[path];
2021-12-11 22:18:48 +05:30
commit(types.SET_CURRENT_DIFF_FILE, fileHash);
2021-09-30 23:02:18 +05:30
2021-10-27 15:23:28 +05:30
if (getters.isVirtualScrollingEnabled) {
2021-09-30 23:02:18 +05:30
eventHub.$emit('scrollToFileHash', fileHash);
2022-04-04 11:22:00 +05:30
setTimeout(() => {
window.history.replaceState(null, null, `#${fileHash}`);
});
2021-09-30 23:02:18 +05:30
} else {
document.location.hash = fileHash;
2021-10-27 15:23:28 +05:30
setTimeout(() => {
handleLocationHash();
});
2021-09-30 23:02:18 +05:30
}
2018-12-05 23:21:45 +05:30
};
2021-02-22 17:27:13 +05:30
export const setShowTreeList = ({ commit }, { showTreeList, saving = true }) => {
commit(types.SET_SHOW_TREE_LIST, showTreeList);
2019-07-07 11:18:12 +05:30
if (saving) {
2021-02-22 17:27:13 +05:30
localStorage.setItem(MR_TREE_SHOW_KEY, showTreeList);
2019-07-07 11:18:12 +05:30
}
2018-12-05 23:21:45 +05:30
};
2018-12-13 13:39:08 +05:30
export const openDiffFileCommentForm = ({ commit, getters }, formData) => {
const form = getters.getCommentFormForDiffFile(formData.fileHash);
if (form) {
commit(types.UPDATE_DIFF_FILE_COMMENT_FORM, formData);
} else {
commit(types.OPEN_DIFF_FILE_COMMENT_FORM, formData);
}
};
export const closeDiffFileCommentForm = ({ commit }, fileHash) => {
commit(types.CLOSE_DIFF_FILE_COMMENT_FORM, fileHash);
};
2021-10-27 15:23:28 +05:30
export const setRenderTreeList = ({ commit }, { renderTreeList, trackClick = true }) => {
2019-03-02 22:35:43 +05:30
commit(types.SET_RENDER_TREE_LIST, renderTreeList);
localStorage.setItem(TREE_LIST_STORAGE_KEY, renderTreeList);
2021-06-08 01:23:25 +05:30
2022-06-21 17:19:12 +05:30
if (trackClick) {
2021-10-27 15:23:28 +05:30
const events = [TRACKING_CLICK_FILE_BROWSER_SETTING];
2021-06-08 01:23:25 +05:30
if (renderTreeList) {
2021-10-27 15:23:28 +05:30
events.push(TRACKING_FILE_BROWSER_TREE);
2021-06-08 01:23:25 +05:30
} else {
2021-10-27 15:23:28 +05:30
events.push(TRACKING_FILE_BROWSER_LIST);
2021-06-08 01:23:25 +05:30
}
2021-10-27 15:23:28 +05:30
queueRedisHllEvents(events);
2021-06-08 01:23:25 +05:30
}
2019-03-02 22:35:43 +05:30
};
2021-09-04 01:27:46 +05:30
export const setShowWhitespace = async (
{ state, commit },
2021-10-27 15:23:28 +05:30
{ url, showWhitespace, updateDatabase = true, trackClick = true },
2021-09-04 01:27:46 +05:30
) => {
2021-09-30 23:02:18 +05:30
if (updateDatabase && Boolean(window.gon?.current_user_id)) {
2021-09-04 01:27:46 +05:30
await axios.put(url || state.endpointUpdateUser, { show_whitespace_in_diffs: showWhitespace });
2019-03-02 22:35:43 +05:30
}
2019-09-04 21:01:54 +05:30
2021-09-04 01:27:46 +05:30
commit(types.SET_SHOW_WHITESPACE, showWhitespace);
2021-01-29 00:20:46 +05:30
notesEventHub.$emit('refetchDiffData');
2021-06-08 01:23:25 +05:30
2022-06-21 17:19:12 +05:30
if (trackClick) {
2021-10-27 15:23:28 +05:30
const events = [TRACKING_CLICK_WHITESPACE_SETTING];
2021-06-08 01:23:25 +05:30
if (showWhitespace) {
2021-10-27 15:23:28 +05:30
events.push(TRACKING_WHITESPACE_SHOW);
2021-06-08 01:23:25 +05:30
} else {
2021-10-27 15:23:28 +05:30
events.push(TRACKING_WHITESPACE_HIDE);
2021-06-08 01:23:25 +05:30
}
2021-10-27 15:23:28 +05:30
queueRedisHllEvents(events);
2021-06-08 01:23:25 +05:30
}
2019-03-02 22:35:43 +05:30
};
export const toggleFileFinder = ({ commit }, visible) => {
commit(types.TOGGLE_FILE_FINDER_VISIBLE, visible);
};
2019-07-07 11:18:12 +05:30
export const cacheTreeListWidth = (_, size) => {
localStorage.setItem(TREE_LIST_WIDTH_STORAGE_KEY, size);
};
export const receiveFullDiffError = ({ commit }, filePath) => {
commit(types.RECEIVE_FULL_DIFF_ERROR, filePath);
2021-09-04 01:27:46 +05:30
createFlash({
message: s__('MergeRequest|Error loading full diff. Please try again.'),
});
2019-07-07 11:18:12 +05:30
};
2021-02-22 17:27:13 +05:30
export const setExpandedDiffLines = ({ commit }, { file, data }) => {
const expandedDiffLines = convertExpandLines({
diffLines: file[INLINE_DIFF_LINES_KEY],
typeKey: TYPE_KEY,
oldLineKey: OLD_LINE_KEY,
newLineKey: NEW_LINE_KEY,
data,
mapLine: ({ line, oldLine, newLine }) =>
Object.assign(line, {
old_line: oldLine,
new_line: newLine,
line_code: `${file.file_hash}_${oldLine}_${newLine}`,
2019-07-31 22:56:46 +05:30
}),
2021-02-22 17:27:13 +05:30
});
2019-07-31 22:56:46 +05:30
2021-02-22 17:27:13 +05:30
if (expandedDiffLines.length > MAX_RENDERING_DIFF_LINES) {
2019-07-31 22:56:46 +05:30
let index = START_RENDERING_INDEX;
commit(types.SET_CURRENT_VIEW_DIFF_FILE_LINES, {
filePath: file.file_path,
2021-02-22 17:27:13 +05:30
lines: expandedDiffLines.slice(0, index),
2019-07-31 22:56:46 +05:30
});
commit(types.TOGGLE_DIFF_FILE_RENDERING_MORE, file.file_path);
2021-03-08 18:12:59 +05:30
const idleCb = (t) => {
2019-07-31 22:56:46 +05:30
const startIndex = index;
while (
t.timeRemaining() >= MIN_RENDERING_MS &&
2021-02-22 17:27:13 +05:30
index !== expandedDiffLines.length &&
2019-07-31 22:56:46 +05:30
index - startIndex !== MAX_RENDERING_BULK_ROWS
) {
2021-02-22 17:27:13 +05:30
const line = expandedDiffLines[index];
2019-07-31 22:56:46 +05:30
if (line) {
commit(types.ADD_CURRENT_VIEW_DIFF_FILE_LINES, { filePath: file.file_path, line });
index += 1;
}
}
2021-02-22 17:27:13 +05:30
if (index !== expandedDiffLines.length) {
2019-07-31 22:56:46 +05:30
idleCallback(idleCb);
} else {
commit(types.TOGGLE_DIFF_FILE_RENDERING_MORE, file.file_path);
}
};
idleCallback(idleCb);
} else {
commit(types.SET_CURRENT_VIEW_DIFF_FILE_LINES, {
filePath: file.file_path,
2021-02-22 17:27:13 +05:30
lines: expandedDiffLines,
2019-07-31 22:56:46 +05:30
});
}
};
2020-06-23 00:09:42 +05:30
export const fetchFullDiff = ({ commit, dispatch }, file) =>
2019-07-07 11:18:12 +05:30
axios
.get(file.context_lines_path, {
params: {
full: true,
from_merge_request: true,
},
})
2019-07-31 22:56:46 +05:30
.then(({ data }) => {
2020-06-23 00:09:42 +05:30
commit(types.RECEIVE_FULL_DIFF_SUCCESS, { filePath: file.file_path });
2019-07-31 22:56:46 +05:30
dispatch('setExpandedDiffLines', { file, data });
})
2019-07-07 11:18:12 +05:30
.catch(() => dispatch('receiveFullDiffError', file.file_path));
2020-06-23 00:09:42 +05:30
export const toggleFullDiff = ({ dispatch, commit, getters, state }, filePath) => {
2021-03-08 18:12:59 +05:30
const file = state.diffFiles.find((f) => f.file_path === filePath);
2019-07-07 11:18:12 +05:30
2020-06-23 00:09:42 +05:30
commit(types.REQUEST_FULL_DIFF, filePath);
2019-07-07 11:18:12 +05:30
if (file.isShowingFullFile) {
dispatch('loadCollapsedDiff', file)
.then(() => dispatch('assignDiscussionsToDiff', getters.getDiffFileDiscussions(file)))
.catch(() => dispatch('receiveFullDiffError', filePath));
} else {
dispatch('fetchFullDiff', file);
}
};
2021-02-22 17:27:13 +05:30
export function switchToFullDiffFromRenamedFile({ commit, dispatch }, { diffFile }) {
2020-05-24 23:13:21 +05:30
return axios
.get(diffFile.context_lines_path, {
params: {
full: true,
from_merge_request: true,
},
})
.then(({ data }) => {
const lines = data.map((line, index) =>
prepareLineForRenamedFile({
2021-02-22 17:27:13 +05:30
diffViewType: 'inline',
2020-05-24 23:13:21 +05:30
line,
diffFile,
index,
}),
);
commit(types.SET_DIFF_FILE_VIEWER, {
filePath: diffFile.file_path,
viewer: {
...diffFile.alternate_viewer,
2021-01-03 14:25:43 +05:30
automaticallyCollapsed: false,
2021-01-29 00:20:46 +05:30
manuallyCollapsed: false,
2020-05-24 23:13:21 +05:30
},
});
commit(types.SET_CURRENT_VIEW_DIFF_FILE_LINES, { filePath: diffFile.file_path, lines });
dispatch('startRenderDiffsQueue');
});
}
2021-01-29 00:20:46 +05:30
export const setFileCollapsedByUser = ({ commit }, { filePath, collapsed }) => {
commit(types.SET_FILE_COLLAPSED, { filePath, collapsed, trigger: DIFF_FILE_MANUAL_COLLAPSE });
};
2019-07-07 11:18:12 +05:30
2022-08-13 15:12:31 +05:30
export const setFileCollapsedAutomatically = ({ commit }, { filePath, collapsed }) => {
commit(types.SET_FILE_COLLAPSED, { filePath, collapsed, trigger: DIFF_FILE_AUTOMATIC_COLLAPSE });
};
2019-09-04 21:01:54 +05:30
export const setSuggestPopoverDismissed = ({ commit, state }) =>
axios
.post(state.dismissEndpoint, {
feature_name: 'suggest_popover_dismissed',
})
.then(() => {
commit(types.SET_SHOW_SUGGEST_POPOVER);
})
.catch(() => {
2021-09-04 01:27:46 +05:30
createFlash({
message: s__('MergeRequest|Error dismissing suggestion popover. Please try again.'),
});
2019-09-04 21:01:54 +05:30
});
2020-05-24 23:13:21 +05:30
export function changeCurrentCommit({ dispatch, commit, state }, { commitId }) {
/* eslint-disable @gitlab/require-i18n-strings */
if (!commitId) {
return Promise.reject(new Error('`commitId` is a required argument'));
} else if (!state.commit) {
return Promise.reject(new Error('`state` must already contain a valid `commit`'));
}
/* eslint-enable @gitlab/require-i18n-strings */
// this is less than ideal, see: https://gitlab.com/gitlab-org/gitlab/-/issues/215421
const commitRE = new RegExp(state.commit.id, 'g');
commit(types.SET_DIFF_FILES, []);
commit(types.SET_BASE_CONFIG, {
...state,
endpoint: state.endpoint.replace(commitRE, commitId),
endpointBatch: state.endpointBatch.replace(commitRE, commitId),
endpointMetadata: state.endpointMetadata.replace(commitRE, commitId),
});
return dispatch('fetchDiffFilesMeta');
}
export function moveToNeighboringCommit({ dispatch, state }, { direction }) {
const previousCommitId = state.commit?.prev_commit_id;
const nextCommitId = state.commit?.next_commit_id;
const canMove = {
next: !state.isLoading && nextCommitId,
previous: !state.isLoading && previousCommitId,
};
let commitId;
if (direction === 'next' && canMove.next) {
commitId = nextCommitId;
} else if (direction === 'previous' && canMove.previous) {
commitId = previousCommitId;
}
if (commitId) {
dispatch('changeCurrentCommit', { commitId });
}
}
2020-10-24 23:57:45 +05:30
export const setCurrentDiffFileIdFromNote = ({ commit, state, rootGetters }, noteId) => {
2020-07-28 23:09:34 +05:30
const note = rootGetters.notesById[noteId];
if (!note) return;
const fileHash = rootGetters.getDiscussion(note.discussion_id).diff_file?.file_hash;
2021-03-08 18:12:59 +05:30
if (fileHash && state.diffFiles.some((f) => f.file_hash === fileHash)) {
2021-12-11 22:18:48 +05:30
commit(types.SET_CURRENT_DIFF_FILE, fileHash);
2020-07-28 23:09:34 +05:30
}
};
export const navigateToDiffFileIndex = ({ commit, state }, index) => {
const fileHash = state.diffFiles[index].file_hash;
document.location.hash = fileHash;
2021-12-11 22:18:48 +05:30
commit(types.SET_CURRENT_DIFF_FILE, fileHash);
2020-07-28 23:09:34 +05:30
};
2021-02-22 17:27:13 +05:30
2021-04-29 21:17:54 +05:30
export const setFileByFile = ({ state, commit }, { fileByFile }) => {
2021-02-22 17:27:13 +05:30
commit(types.SET_FILE_BY_FILE, fileByFile);
2021-04-29 21:17:54 +05:30
2022-06-21 17:19:12 +05:30
const events = [TRACKING_CLICK_SINGLE_FILE_SETTING];
2021-10-27 15:23:28 +05:30
2022-06-21 17:19:12 +05:30
if (fileByFile) {
events.push(TRACKING_SINGLE_FILE_MODE);
} else {
events.push(TRACKING_MULTIPLE_FILES_MODE);
2021-06-08 01:23:25 +05:30
}
2022-06-21 17:19:12 +05:30
queueRedisHllEvents(events);
2021-04-29 21:17:54 +05:30
return axios
.put(state.endpointUpdateUser, {
view_diffs_file_by_file: fileByFile,
})
.then(() => {
// https://gitlab.com/gitlab-org/gitlab/-/issues/326961
// We can't even do a simple console warning here because
// the pipeline will fail. However, the issue above will
// eventually handle errors appropriately.
// console.warn('Saving the file-by-fil user preference failed.');
});
2021-02-22 17:27:13 +05:30
};
2021-03-08 18:12:59 +05:30
2021-03-11 19:13:27 +05:30
export function reviewFile({ commit, state }, { file, reviewed = true }) {
2021-03-08 18:12:59 +05:30
const { mrPath } = getDerivedMergeRequestInformation({ endpoint: file.load_collapsed_diff_url });
2021-03-11 19:13:27 +05:30
const reviews = markFileReview(state.mrReviews, file, reviewed);
2021-03-08 18:12:59 +05:30
2021-03-11 19:13:27 +05:30
setReviewsForMergeRequest(mrPath, reviews);
2021-12-11 22:18:48 +05:30
commit(types.SET_DIFF_FILE_VIEWED, { id: file.file_hash, seen: reviewed });
2021-03-08 18:12:59 +05:30
commit(types.SET_MR_FILE_REVIEWS, reviews);
}
2021-10-27 15:23:28 +05:30
export const disableVirtualScroller = ({ commit }) => commit(types.DISABLE_VIRTUAL_SCROLLING);