diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-08-19 09:08:42 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-08-19 09:08:42 +0000 |
commit | b76ae638462ab0f673e5915986070518dd3f9ad3 (patch) | |
tree | bdab0533383b52873be0ec0eb4d3c66598ff8b91 /app/assets/javascripts/diffs | |
parent | 434373eabe7b4be9593d18a585fb763f1e5f1a6f (diff) | |
download | gitlab-ce-b76ae638462ab0f673e5915986070518dd3f9ad3.tar.gz |
Add latest changes from gitlab-org/gitlab@14-2-stable-eev14.2.0-rc42
Diffstat (limited to 'app/assets/javascripts/diffs')
-rw-r--r-- | app/assets/javascripts/diffs/components/app.vue | 94 | ||||
-rw-r--r-- | app/assets/javascripts/diffs/components/diff_file.vue | 99 | ||||
-rw-r--r-- | app/assets/javascripts/diffs/components/diff_gutter_avatars.vue | 1 | ||||
-rw-r--r-- | app/assets/javascripts/diffs/components/diff_row.vue | 19 | ||||
-rw-r--r-- | app/assets/javascripts/diffs/components/diff_stats.vue | 4 | ||||
-rw-r--r-- | app/assets/javascripts/diffs/components/settings_dropdown.vue | 4 | ||||
-rw-r--r-- | app/assets/javascripts/diffs/constants.js | 2 | ||||
-rw-r--r-- | app/assets/javascripts/diffs/i18n.js | 22 | ||||
-rw-r--r-- | app/assets/javascripts/diffs/index.js | 16 | ||||
-rw-r--r-- | app/assets/javascripts/diffs/store/actions.js | 50 | ||||
-rw-r--r-- | app/assets/javascripts/diffs/store/getters.js | 22 | ||||
-rw-r--r-- | app/assets/javascripts/diffs/store/modules/diff_state.js | 1 | ||||
-rw-r--r-- | app/assets/javascripts/diffs/store/mutation_types.js | 1 | ||||
-rw-r--r-- | app/assets/javascripts/diffs/store/mutations.js | 3 | ||||
-rw-r--r-- | app/assets/javascripts/diffs/utils/queue_events.js | 13 |
15 files changed, 278 insertions, 73 deletions
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index e33b60f8ab5..d03b5cbc26b 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -14,9 +14,11 @@ import { } from '~/behaviors/shortcuts/keybindings'; import createFlash from '~/flash'; import { isSingleViewStyle } from '~/helpers/diffs_helper'; +import { helpPagePath } from '~/helpers/help_page_helper'; import { parseBoolean } from '~/lib/utils/common_utils'; import { updateHistory } from '~/lib/utils/url_utility'; import { __ } from '~/locale'; +import MrWidgetHowToMergeModal from '~/vue_merge_request_widget/components/mr_widget_how_to_merge_modal.vue'; import PanelResizer from '~/vue_shared/components/panel_resizer.vue'; import notesEventHub from '../../notes/event_hub'; @@ -46,12 +48,12 @@ import diffsEventHub from '../event_hub'; import { reviewStatuses } from '../utils/file_reviews'; import { diffsApp } from '../utils/performance'; import { fileByFile } from '../utils/preferences'; +import { queueRedisHllEvents } from '../utils/queue_events'; import CollapsedFilesWarning from './collapsed_files_warning.vue'; import CommitWidget from './commit_widget.vue'; import CompareVersions from './compare_versions.vue'; import DiffFile from './diff_file.vue'; import HiddenFilesWarning from './hidden_files_warning.vue'; -import MergeConflictWarning from './merge_conflict_warning.vue'; import NoChanges from './no_changes.vue'; import PreRenderer from './pre_renderer.vue'; import TreeList from './tree_list.vue'; @@ -64,7 +66,6 @@ export default { DiffFile, NoChanges, HiddenFilesWarning, - MergeConflictWarning, CollapsedFilesWarning, CommitWidget, TreeList, @@ -76,6 +77,7 @@ export default { DynamicScrollerItem, PreRenderer, VirtualScrollerScrollSync, + MrWidgetHowToMergeModal, }, alerts: { ALERT_OVERFLOW_HIDDEN, @@ -163,6 +165,21 @@ export default { required: false, default: () => ({}), }, + sourceProjectDefaultUrl: { + type: String, + required: false, + default: '', + }, + sourceProjectFullPath: { + type: String, + required: false, + default: '', + }, + isForked: { + type: Boolean, + required: false, + default: false, + }, }, data() { const treeWidth = @@ -172,7 +189,6 @@ export default { treeWidth, diffFilesLength: 0, virtualScrollCurrentIndex: -1, - disableVirtualScroller: false, }; }, computed: { @@ -203,6 +219,8 @@ export default { 'mrReviews', 'renderTreeList', 'showWhitespace', + 'targetBranchName', + 'branchName', ]), ...mapGetters('diffs', [ 'whichCollapsedTypes', @@ -337,29 +355,33 @@ export default { } if (window.gon?.features?.diffSettingsUsageData) { + const events = []; + if (this.renderTreeList) { - api.trackRedisHllUserEvent(TRACKING_FILE_BROWSER_TREE); + events.push(TRACKING_FILE_BROWSER_TREE); } else { - api.trackRedisHllUserEvent(TRACKING_FILE_BROWSER_LIST); + events.push(TRACKING_FILE_BROWSER_LIST); } if (this.diffViewType === INLINE_DIFF_VIEW_TYPE) { - api.trackRedisHllUserEvent(TRACKING_DIFF_VIEW_INLINE); + events.push(TRACKING_DIFF_VIEW_INLINE); } else { - api.trackRedisHllUserEvent(TRACKING_DIFF_VIEW_PARALLEL); + events.push(TRACKING_DIFF_VIEW_PARALLEL); } if (this.showWhitespace) { - api.trackRedisHllUserEvent(TRACKING_WHITESPACE_SHOW); + events.push(TRACKING_WHITESPACE_SHOW); } else { - api.trackRedisHllUserEvent(TRACKING_WHITESPACE_HIDE); + events.push(TRACKING_WHITESPACE_HIDE); } if (this.viewDiffsFileByFile) { - api.trackRedisHllUserEvent(TRACKING_SINGLE_FILE_MODE); + events.push(TRACKING_SINGLE_FILE_MODE); } else { - api.trackRedisHllUserEvent(TRACKING_MULTIPLE_FILES_MODE); + events.push(TRACKING_MULTIPLE_FILES_MODE); } + + queueRedisHllEvents(events); } }, beforeCreate() { @@ -414,6 +436,7 @@ export default { 'setShowTreeList', 'navigateToDiffFileIndex', 'setFileByFile', + 'disableVirtualScroller', ]), subscribeToEvents() { notesEventHub.$once('fetchDiffData', this.fetchData); @@ -506,9 +529,32 @@ export default { ); } - Mousetrap.bind(['ctrl+f', 'command+f'], () => { - this.disableVirtualScroller = true; - }); + if ( + window.gon?.features?.diffsVirtualScrolling || + window.gon?.features?.diffSearchingUsageData + ) { + let keydownTime; + Mousetrap.bind(['mod+f', 'mod+g'], () => { + keydownTime = new Date().getTime(); + }); + + window.addEventListener('blur', () => { + if (keydownTime) { + const delta = new Date().getTime() - keydownTime; + + // To make sure the user is using the find function we need to wait for blur + // and max 1000ms to be sure it the search box is filtered + if (delta >= 0 && delta < 1000) { + this.disableVirtualScroller(); + + if (window.gon?.features?.diffSearchingUsageData) { + api.trackRedisHllUserEvent('i_code_review_user_searches_diff'); + api.trackRedisCounterEvent('diff_searches'); + } + } + } + }); + } }, removeEventListeners() { Mousetrap.unbind(keysFor(MR_PREVIOUS_FILE_IN_DIFF)); @@ -568,6 +614,9 @@ export default { }, minTreeWidth: MIN_TREE_WIDTH, maxTreeWidth: MAX_TREE_WIDTH, + howToMergeDocsPath: helpPagePath('user/project/merge_requests/reviews/index.md', { + anchor: 'checkout-merge-requests-locally-through-the-head-ref', + }), }; </script> @@ -587,12 +636,6 @@ export default { :plain-diff-path="plainDiffPath" :email-patch-path="emailPatchPath" /> - <merge-conflict-warning - v-if="visibleWarning == $options.alerts.ALERT_MERGE_CONFLICT" - :limited="isLimitedContainer" - :resolution-path="conflictResolutionPath" - :mergeable="canMerge" - /> <collapsed-files-warning v-if="visibleWarning == $options.alerts.ALERT_COLLAPSED_FILES" :limited="isLimitedContainer" @@ -628,7 +671,7 @@ export default { <div v-if="isBatchLoading" class="loading"><gl-loading-icon size="lg" /></div> <template v-else-if="renderDiffFiles"> <dynamic-scroller - v-if="!disableVirtualScroller && isVirtualScrollingEnabled" + v-if="isVirtualScrollingEnabled" ref="virtualScroller" :items="diffs" :min-item-size="70" @@ -705,6 +748,15 @@ export default { <no-changes v-else :changes-empty-state-illustration="changesEmptyStateIllustration" /> </div> </div> + <mr-widget-how-to-merge-modal + :is-fork="isForked" + :can-merge="canMerge" + :source-branch="branchName" + :source-project-path="sourceProjectFullPath" + :target-branch="targetBranchName" + :source-project-default-url="sourceProjectDefaultUrl" + :reviewing-docs-path="$options.howToMergeDocsPath" + /> </div> </div> </template> diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index dde5ea81e9a..933891d698c 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -1,5 +1,12 @@ <script> -import { GlButton, GlLoadingIcon, GlSafeHtmlDirective as SafeHtml, GlSprintf } from '@gitlab/ui'; +import { + GlButton, + GlLoadingIcon, + GlSafeHtmlDirective as SafeHtml, + GlSprintf, + GlAlert, + GlModalDirective, +} from '@gitlab/ui'; import { escape } from 'lodash'; import { mapActions, mapGetters, mapState } from 'vuex'; import { IdState } from 'vendor/vue-virtual-scroller'; @@ -19,7 +26,7 @@ import { EVT_PERF_MARK_FIRST_DIFF_FILE_SHOWN, } from '../constants'; import eventHub from '../event_hub'; -import { DIFF_FILE, GENERIC_ERROR } from '../i18n'; +import { DIFF_FILE, GENERIC_ERROR, CONFLICT_TEXT } from '../i18n'; import { collapsedType, getShortShaFromFile } from '../utils/diff_file'; import DiffContent from './diff_content.vue'; import DiffFileHeader from './diff_file_header.vue'; @@ -31,9 +38,11 @@ export default { GlButton, GlLoadingIcon, GlSprintf, + GlAlert, }, directives: { SafeHtml, + GlModalDirective, }, mixins: [glFeatureFlagsMixin(), IdState({ idProp: (vm) => vm.file.file_hash })], props: { @@ -83,6 +92,7 @@ export default { idState() { return { isLoadingCollapsedDiff: false, + hasLoadedCollapsedDiff: false, forkMessageVisible: false, hasToggled: false, }; @@ -92,7 +102,12 @@ export default { genericError: GENERIC_ERROR, }, computed: { - ...mapState('diffs', ['currentDiffFileId', 'codequalityDiff']), + ...mapState('diffs', [ + 'currentDiffFileId', + 'codequalityDiff', + 'conflictResolutionPath', + 'canMerge', + ]), ...mapGetters(['isNotesFetched']), ...mapGetters('diffs', ['getDiffFileDiscussions', 'isVirtualScrollingEnabled']), viewBlobHref() { @@ -181,7 +196,13 @@ export default { }, 'file.file_hash': { handler: function hashChangeWatch(newHash, oldHash) { - if (newHash && oldHash && !this.hasDiff && !this.preRender) { + if ( + newHash && + oldHash && + !this.hasDiff && + !this.preRender && + !this.idState.hasLoadedCollapsedDiff + ) { this.requestDiff(); } }, @@ -198,6 +219,8 @@ export default { if (this.hasDiff) { this.postRender(); + } else if (this.viewDiffsFileByFile && !this.isCollapsed) { + this.requestDiff(); } this.manageViewedEffects(); @@ -265,14 +288,22 @@ export default { } }, requestDiff() { - this.idState.isLoadingCollapsedDiff = true; + const { idState, file } = this; - this.loadCollapsedDiff(this.file) + idState.isLoadingCollapsedDiff = true; + + this.loadCollapsedDiff(file) .then(() => { - this.idState.isLoadingCollapsedDiff = false; - this.setRenderIt(this.file); + idState.isLoadingCollapsedDiff = false; + idState.hasLoadedCollapsedDiff = true; + + if (this.file.file_hash === file.file_hash) { + this.setRenderIt(this.file); + } }) .then(() => { + if (this.file.file_hash !== file.file_hash) return; + requestIdleCallback( () => { this.postRender(); @@ -282,7 +313,7 @@ export default { ); }) .catch(() => { - this.idState.isLoadingCollapsedDiff = false; + idState.isLoadingCollapsedDiff = false; createFlash({ message: this.$options.i18n.genericError, }); @@ -295,6 +326,7 @@ export default { this.idState.forkMessageVisible = false; }, }, + CONFLICT_TEXT, }; </script> @@ -373,6 +405,55 @@ export default { <div v-else v-safe-html="errorMessage" class="nothing-here-block"></div> </div> <template v-else> + <gl-alert + v-if="file.conflict_type" + variant="danger" + :dismissible="false" + data-testid="conflictsAlert" + > + {{ $options.CONFLICT_TEXT[file.conflict_type] }} + <template v-if="!canMerge"> + {{ __('Ask someone with write access to resolve it.') }} + </template> + <gl-sprintf + v-else-if="conflictResolutionPath" + :message=" + __( + 'You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}.', + ) + " + > + <template #gitlabLink="{ content }"> + <gl-button + :href="conflictResolutionPath" + variant="link" + class="gl-vertical-align-text-bottom" + >{{ content }}</gl-button + > + </template> + <template #resolveLocally="{ content }"> + <gl-button + v-gl-modal-directive="'modal-merge-info'" + variant="link" + class="gl-vertical-align-text-bottom" + >{{ content }}</gl-button + > + </template> + </gl-sprintf> + <gl-sprintf + v-else + :message="__('You can %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}.')" + > + <template #resolveLocally="{ content }"> + <gl-button + v-gl-modal-directive="'modal-merge-info'" + variant="link" + class="gl-vertical-align-text-bottom" + >{{ content }}</gl-button + > + </template> + </gl-sprintf> + </gl-alert> <div v-if="showWarning" class="collapsed-file-warning gl-p-7 gl-bg-orange-50 gl-text-center gl-rounded-bottom-left-base gl-rounded-bottom-right-base" diff --git a/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue b/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue index 1f3ec7092bc..e2f3f9cad7b 100644 --- a/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue +++ b/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue @@ -75,6 +75,7 @@ export default { :key="note.id" :img-src="note.author.avatar_url" :tooltip-text="getTooltipText(note)" + lazy class="diff-comment-avatar js-diff-comment-avatar" @click.native="$emit('toggleLineDiscussions')" /> diff --git a/app/assets/javascripts/diffs/components/diff_row.vue b/app/assets/javascripts/diffs/components/diff_row.vue index c310bd9f31a..db3ad074d2f 100644 --- a/app/assets/javascripts/diffs/components/diff_row.vue +++ b/app/assets/javascripts/diffs/components/diff_row.vue @@ -134,22 +134,13 @@ export default { interopRightAttributes(props) { return getInteropNewSideAttributes(props.line.right); }, - conflictText: memoize( - (line) => { + lineContent: (line) => { + if (line.isConflictMarker) { return line.type === CONFLICT_MARKER_THEIR ? 'HEAD//our changes' : 'origin//their changes'; - }, - (line) => line.type, - ), - lineContent: memoize( - (line) => { - if (line.isConflictMarker) { - return line.type === CONFLICT_MARKER_THEIR ? 'HEAD//our changes' : 'origin//their changes'; - } + } - return line.rich_text; - }, - (line) => line.line_code, - ), + return line.rich_text; + }, CONFLICT_MARKER, CONFLICT_MARKER_THEIR, CONFLICT_OUR, diff --git a/app/assets/javascripts/diffs/components/diff_stats.vue b/app/assets/javascripts/diffs/components/diff_stats.vue index 05d4fbe7c20..e8b4ff16aec 100644 --- a/app/assets/javascripts/diffs/components/diff_stats.vue +++ b/app/assets/javascripts/diffs/components/diff_stats.vue @@ -62,8 +62,8 @@ export default { </div> <div v-else class="diff-stats-contents"> <div v-if="hasDiffFiles" class="diff-stats-group"> - <gl-icon name="doc-code" class="diff-stats-icon text-secondary" /> - <span class="text-secondary bold">{{ diffFilesCountText }} {{ filesText }}</span> + <gl-icon name="doc-code" class="diff-stats-icon gl-text-gray-500" /> + <span class="gl-text-gray-500 bold">{{ diffFilesCountText }} {{ filesText }}</span> </div> <div class="diff-stats-group gl-text-green-600 gl-display-flex gl-align-items-center" diff --git a/app/assets/javascripts/diffs/components/settings_dropdown.vue b/app/assets/javascripts/diffs/components/settings_dropdown.vue index 178f93b651e..2d9ac76b3e4 100644 --- a/app/assets/javascripts/diffs/components/settings_dropdown.vue +++ b/app/assets/javascripts/diffs/components/settings_dropdown.vue @@ -60,14 +60,14 @@ export default { <gl-button :class="{ selected: !renderTreeList }" class="gl-w-half js-list-view" - @click="setRenderTreeList(false)" + @click="setRenderTreeList({ renderTreeList: false })" > {{ __('List view') }} </gl-button> <gl-button :class="{ selected: renderTreeList }" class="gl-w-half js-tree-view" - @click="setRenderTreeList(true)" + @click="setRenderTreeList({ renderTreeList: true })" > {{ __('Tree view') }} </gl-button> diff --git a/app/assets/javascripts/diffs/constants.js b/app/assets/javascripts/diffs/constants.js index f1cf556fde0..8dda5eadb16 100644 --- a/app/assets/javascripts/diffs/constants.js +++ b/app/assets/javascripts/diffs/constants.js @@ -111,6 +111,8 @@ export const CONFLICT_MARKER_OUR = 'conflict_marker_our'; export const CONFLICT_MARKER_THEIR = 'conflict_marker_their'; // Tracking events +export const DEFER_DURATION = 750; + export const TRACKING_CLICK_DIFF_VIEW_SETTING = 'i_code_review_click_diff_view_setting'; export const TRACKING_DIFF_VIEW_INLINE = 'i_code_review_diff_view_inline'; export const TRACKING_DIFF_VIEW_PARALLEL = 'i_code_review_diff_view_parallel'; diff --git a/app/assets/javascripts/diffs/i18n.js b/app/assets/javascripts/diffs/i18n.js index a45fd92d0a9..e617890af2e 100644 --- a/app/assets/javascripts/diffs/i18n.js +++ b/app/assets/javascripts/diffs/i18n.js @@ -25,3 +25,25 @@ export const SETTINGS_DROPDOWN = { fileByFile: __('Show one file at a time'), preferences: __('Preferences'), }; + +export const CONFLICT_TEXT = { + both_modified: __('Conflict: This file was modified in both the source and target branches.'), + modified_source_removed_target: __( + 'Conflict: This file was modified in the source branch, but removed in the target branch.', + ), + modified_target_removed_source: __( + 'Conflict: This file was removed in the source branch, but modified in the target branch.', + ), + renamed_same_file: __( + 'Conflict: This file was renamed differently in the source and target branches.', + ), + removed_source_renamed_target: __( + 'Conflict: This file was removed in the source branch, but renamed in the target branch.', + ), + removed_target_renamed_source: __( + 'Conflict: This file was renamed in the source branch, but removed in the target branch.', + ), + both_added: __( + 'Conflict: This file was added both in the source and target branches, but with different contents.', + ), +}; diff --git a/app/assets/javascripts/diffs/index.js b/app/assets/javascripts/diffs/index.js index ea83523008c..bddc28c4758 100644 --- a/app/assets/javascripts/diffs/index.js +++ b/app/assets/javascripts/diffs/index.js @@ -2,6 +2,7 @@ import Cookies from 'js-cookie'; import Vue from 'vue'; import { mapActions, mapState, mapGetters } from 'vuex'; import { parseBoolean } from '~/lib/utils/common_utils'; +import { getParameterValues } from '~/lib/utils/url_utility'; import FindFile from '~/vue_shared/components/file_finder/index.vue'; import eventHub from '../notes/event_hub'; import diffsApp from './components/app.vue'; @@ -82,6 +83,9 @@ export default function initDiffsApp(store) { showWhitespaceDefault: parseBoolean(dataset.showWhitespaceDefault), viewDiffsFileByFile: parseBoolean(dataset.fileByFileDefault), defaultSuggestionCommitMessage: dataset.defaultSuggestionCommitMessage, + sourceProjectDefaultUrl: dataset.sourceProjectDefaultUrl, + sourceProjectFullPath: dataset.sourceProjectFullPath, + isForked: parseBoolean(dataset.isForked), }; }, computed: { @@ -93,7 +97,7 @@ export default function initDiffsApp(store) { const treeListStored = localStorage.getItem(TREE_LIST_STORAGE_KEY); const renderTreeList = treeListStored !== null ? parseBoolean(treeListStored) : true; - this.setRenderTreeList(renderTreeList); + this.setRenderTreeList({ renderTreeList, trackClick: false }); // NOTE: A "true" or "checked" value for `showWhitespace` is '0' not '1'. // Check for cookie and save that setting for future use. @@ -104,6 +108,7 @@ export default function initDiffsApp(store) { this.setShowWhitespace({ url: this.endpointUpdateUser, showWhitespace: hideWhitespace !== '1', + trackClick: false, }); Cookies.remove(DIFF_WHITESPACE_COOKIE_NAME); } else { @@ -111,8 +116,14 @@ export default function initDiffsApp(store) { this.setShowWhitespace({ showWhitespace: this.showWhitespaceDefault, updateDatabase: false, + trackClick: false, }); } + + const vScrollingParam = getParameterValues('virtual_scrolling')[0]; + if (vScrollingParam === 'false' || vScrollingParam === 'true') { + Cookies.set('diffs_virtual_scrolling', vScrollingParam); + } }, methods: { ...mapActions('diffs', ['setRenderTreeList', 'setShowWhitespace']), @@ -139,6 +150,9 @@ export default function initDiffsApp(store) { fileByFileUserPreference: this.viewDiffsFileByFile, defaultSuggestionCommitMessage: this.defaultSuggestionCommitMessage, rehydratedMrReviews: getReviewsForMergeRequest(mrPath), + sourceProjectDefaultUrl: this.sourceProjectDefaultUrl, + sourceProjectFullPath: this.sourceProjectFullPath, + isForked: this.isForked, }, }); }, diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index 66510edf3db..f7bdbe94bac 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -1,6 +1,5 @@ import Cookies from 'js-cookie'; import Vue from 'vue'; -import api from '~/api'; import createFlash from '~/flash'; import { diffViewerModes } from '~/ide/constants'; import axios from '~/lib/utils/axios_utils'; @@ -50,6 +49,7 @@ import eventHub from '../event_hub'; import { isCollapsed } from '../utils/diff_file'; import { markFileReview, setReviewsForMergeRequest } from '../utils/file_reviews'; import { getDerivedMergeRequestInformation } from '../utils/merge_request'; +import { queueRedisHllEvents } from '../utils/queue_events'; import TreeWorker from '../workers/tree_worker'; import * as types from './mutation_types'; import { @@ -368,8 +368,7 @@ export const setInlineDiffViewType = ({ commit }) => { historyPushState(url); if (window.gon?.features?.diffSettingsUsageData) { - api.trackRedisHllUserEvent(TRACKING_CLICK_DIFF_VIEW_SETTING); - api.trackRedisHllUserEvent(TRACKING_DIFF_VIEW_INLINE); + queueRedisHllEvents([TRACKING_CLICK_DIFF_VIEW_SETTING, TRACKING_DIFF_VIEW_INLINE]); } }; @@ -381,8 +380,7 @@ export const setParallelDiffViewType = ({ commit }) => { historyPushState(url); if (window.gon?.features?.diffSettingsUsageData) { - api.trackRedisHllUserEvent(TRACKING_CLICK_DIFF_VIEW_SETTING); - api.trackRedisHllUserEvent(TRACKING_DIFF_VIEW_PARALLEL); + queueRedisHllEvents([TRACKING_CLICK_DIFF_VIEW_SETTING, TRACKING_DIFF_VIEW_PARALLEL]); } }; @@ -520,14 +518,14 @@ export const toggleActiveFileByHash = ({ commit }, hash) => { commit(types.VIEW_DIFF_FILE, hash); }; -export const scrollToFile = ({ state, commit }, path) => { +export const scrollToFile = ({ state, commit, getters }, path) => { if (!state.treeEntries[path]) return; const { fileHash } = state.treeEntries[path]; commit(types.VIEW_DIFF_FILE, fileHash); - if (window.gon?.features?.diffsVirtualScrolling) { + if (getters.isVirtualScrollingEnabled) { eventHub.$emit('scrollToFileHash', fileHash); setTimeout(() => { @@ -535,6 +533,10 @@ export const scrollToFile = ({ state, commit }, path) => { }); } else { document.location.hash = fileHash; + + setTimeout(() => { + handleLocationHash(); + }); } }; @@ -560,25 +562,27 @@ export const closeDiffFileCommentForm = ({ commit }, fileHash) => { commit(types.CLOSE_DIFF_FILE_COMMENT_FORM, fileHash); }; -export const setRenderTreeList = ({ commit }, renderTreeList) => { +export const setRenderTreeList = ({ commit }, { renderTreeList, trackClick = true }) => { commit(types.SET_RENDER_TREE_LIST, renderTreeList); localStorage.setItem(TREE_LIST_STORAGE_KEY, renderTreeList); - if (window.gon?.features?.diffSettingsUsageData) { - api.trackRedisHllUserEvent(TRACKING_CLICK_FILE_BROWSER_SETTING); + if (window.gon?.features?.diffSettingsUsageData && trackClick) { + const events = [TRACKING_CLICK_FILE_BROWSER_SETTING]; if (renderTreeList) { - api.trackRedisHllUserEvent(TRACKING_FILE_BROWSER_TREE); + events.push(TRACKING_FILE_BROWSER_TREE); } else { - api.trackRedisHllUserEvent(TRACKING_FILE_BROWSER_LIST); + events.push(TRACKING_FILE_BROWSER_LIST); } + + queueRedisHllEvents(events); } }; export const setShowWhitespace = async ( { state, commit }, - { url, showWhitespace, updateDatabase = true }, + { url, showWhitespace, updateDatabase = true, trackClick = true }, ) => { if (updateDatabase && Boolean(window.gon?.current_user_id)) { await axios.put(url || state.endpointUpdateUser, { show_whitespace_in_diffs: showWhitespace }); @@ -587,14 +591,16 @@ export const setShowWhitespace = async ( commit(types.SET_SHOW_WHITESPACE, showWhitespace); notesEventHub.$emit('refetchDiffData'); - if (window.gon?.features?.diffSettingsUsageData) { - api.trackRedisHllUserEvent(TRACKING_CLICK_WHITESPACE_SETTING); + if (window.gon?.features?.diffSettingsUsageData && trackClick) { + const events = [TRACKING_CLICK_WHITESPACE_SETTING]; if (showWhitespace) { - api.trackRedisHllUserEvent(TRACKING_WHITESPACE_SHOW); + events.push(TRACKING_WHITESPACE_SHOW); } else { - api.trackRedisHllUserEvent(TRACKING_WHITESPACE_HIDE); + events.push(TRACKING_WHITESPACE_HIDE); } + + queueRedisHllEvents(events); } }; @@ -815,13 +821,15 @@ export const setFileByFile = ({ state, commit }, { fileByFile }) => { Cookies.set(DIFF_FILE_BY_FILE_COOKIE_NAME, fileViewMode); if (window.gon?.features?.diffSettingsUsageData) { - api.trackRedisHllUserEvent(TRACKING_CLICK_SINGLE_FILE_SETTING); + const events = [TRACKING_CLICK_SINGLE_FILE_SETTING]; if (fileByFile) { - api.trackRedisHllUserEvent(TRACKING_SINGLE_FILE_MODE); + events.push(TRACKING_SINGLE_FILE_MODE); } else { - api.trackRedisHllUserEvent(TRACKING_MULTIPLE_FILES_MODE); + events.push(TRACKING_MULTIPLE_FILES_MODE); } + + queueRedisHllEvents(events); } return axios @@ -844,3 +852,5 @@ export function reviewFile({ commit, state }, { file, reviewed = true }) { setReviewsForMergeRequest(mrPath, reviews); commit(types.SET_MR_FILE_REVIEWS, reviews); } + +export const disableVirtualScroller = ({ commit }) => commit(types.DISABLE_VIRTUAL_SCROLLING); diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js index 1b6a673925f..18bd8e5f1d8 100644 --- a/app/assets/javascripts/diffs/store/getters.js +++ b/app/assets/javascripts/diffs/store/getters.js @@ -1,3 +1,4 @@ +import Cookies from 'js-cookie'; import { getParameterValues } from '~/lib/utils/url_utility'; import { __, n__ } from '~/locale'; import { @@ -173,7 +174,20 @@ export function suggestionCommitMessage(state, _, rootState) { }); } -export const isVirtualScrollingEnabled = (state) => - !state.viewDiffsFileByFile && - (window.gon?.features?.diffsVirtualScrolling || - getParameterValues('virtual_scrolling')[0] === 'true'); +export const isVirtualScrollingEnabled = (state) => { + const vSrollerCookie = Cookies.get('diffs_virtual_scrolling'); + + if (state.disableVirtualScroller) { + return false; + } + + if (vSrollerCookie) { + return vSrollerCookie === 'true'; + } + + return ( + !state.viewDiffsFileByFile && + (window.gon?.features?.diffsVirtualScrolling || + getParameterValues('virtual_scrolling')[0] === 'true') + ); +}; diff --git a/app/assets/javascripts/diffs/store/modules/diff_state.js b/app/assets/javascripts/diffs/store/modules/diff_state.js index 348dd452698..d76361513d4 100644 --- a/app/assets/javascripts/diffs/store/modules/diff_state.js +++ b/app/assets/javascripts/diffs/store/modules/diff_state.js @@ -43,4 +43,5 @@ export default () => ({ defaultSuggestionCommitMessage: '', mrReviews: {}, latestDiff: true, + disableVirtualScroller: false, }); diff --git a/app/assets/javascripts/diffs/store/mutation_types.js b/app/assets/javascripts/diffs/store/mutation_types.js index 4641731c4b6..2c370221f40 100644 --- a/app/assets/javascripts/diffs/store/mutation_types.js +++ b/app/assets/javascripts/diffs/store/mutation_types.js @@ -47,3 +47,4 @@ export const SET_DIFF_FILE_VIEWER = 'SET_DIFF_FILE_VIEWER'; export const SET_SHOW_SUGGEST_POPOVER = 'SET_SHOW_SUGGEST_POPOVER'; export const TOGGLE_LINE_DISCUSSIONS = 'TOGGLE_LINE_DISCUSSIONS'; +export const DISABLE_VIRTUAL_SCROLLING = 'DISABLE_VIRTUAL_SCROLLING'; diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index 9ff9a02d444..1aa83453bf7 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -362,4 +362,7 @@ export default { [types.SET_MR_FILE_REVIEWS](state, newReviews) { state.mrReviews = newReviews; }, + [types.DISABLE_VIRTUAL_SCROLLING](state) { + state.disableVirtualScroller = true; + }, }; diff --git a/app/assets/javascripts/diffs/utils/queue_events.js b/app/assets/javascripts/diffs/utils/queue_events.js new file mode 100644 index 00000000000..08fcc98d45f --- /dev/null +++ b/app/assets/javascripts/diffs/utils/queue_events.js @@ -0,0 +1,13 @@ +import { delay } from 'lodash'; +import api from '~/api'; +import { DEFER_DURATION } from '../constants'; + +function trackRedisHllUserEvent(event, deferDuration = 0) { + delay(() => api.trackRedisHllUserEvent(event), deferDuration); +} + +export function queueRedisHllEvents(events) { + events.forEach((event, index) => { + trackRedisHllUserEvent(event, DEFER_DURATION * (index + 1)); + }); +} |