diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-19 15:44:42 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-19 15:44:42 +0000 |
commit | 4555e1b21c365ed8303ffb7a3325d773c9b8bf31 (patch) | |
tree | 5423a1c7516cffe36384133ade12572cf709398d /app/assets/javascripts/diffs | |
parent | e570267f2f6b326480d284e0164a6464ba4081bc (diff) | |
download | gitlab-ce-4555e1b21c365ed8303ffb7a3325d773c9b8bf31.tar.gz |
Add latest changes from gitlab-org/gitlab@13-12-stable-eev13.12.0-rc42
Diffstat (limited to 'app/assets/javascripts/diffs')
17 files changed, 273 insertions, 169 deletions
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 7c610968209..6a3f5993a22 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -3,6 +3,8 @@ import { GlLoadingIcon, GlPagination, GlSprintf } from '@gitlab/ui'; import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils'; import Mousetrap from 'mousetrap'; import { mapState, mapGetters, mapActions } from 'vuex'; +import { DynamicScroller, DynamicScrollerItem } from 'vendor/vue-virtual-scroller'; +import api from '~/api'; import { keysFor, MR_PREVIOUS_FILE_IN_DIFF, @@ -16,7 +18,6 @@ import { getParameterByName, parseBoolean } from '~/lib/utils/common_utils'; import { updateHistory } from '~/lib/utils/url_utility'; import { __ } from '~/locale'; import PanelResizer from '~/vue_shared/components/panel_resizer.vue'; -import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import notesEventHub from '../../notes/event_hub'; import { @@ -30,6 +31,15 @@ import { ALERT_OVERFLOW_HIDDEN, ALERT_MERGE_CONFLICT, ALERT_COLLAPSED_FILES, + INLINE_DIFF_VIEW_TYPE, + TRACKING_DIFF_VIEW_INLINE, + TRACKING_DIFF_VIEW_PARALLEL, + TRACKING_FILE_BROWSER_TREE, + TRACKING_FILE_BROWSER_LIST, + TRACKING_WHITESPACE_SHOW, + TRACKING_WHITESPACE_HIDE, + TRACKING_SINGLE_FILE_MODE, + TRACKING_MULTIPLE_FILES_MODE, } from '../constants'; import { reviewStatuses } from '../utils/file_reviews'; @@ -59,8 +69,9 @@ export default { PanelResizer, GlPagination, GlSprintf, + DynamicScroller, + DynamicScrollerItem, }, - mixins: [glFeatureFlagsMixin()], alerts: { ALERT_OVERFLOW_HIDDEN, ALERT_MERGE_CONFLICT, @@ -183,8 +194,15 @@ export default { 'hasConflicts', 'viewDiffsFileByFile', 'mrReviews', + 'renderTreeList', + 'showWhitespace', + ]), + ...mapGetters('diffs', [ + 'whichCollapsedTypes', + 'isParallelView', + 'currentDiffIndex', + 'isVirtualScrollingEnabled', ]), - ...mapGetters('diffs', ['whichCollapsedTypes', 'isParallelView', 'currentDiffIndex']), ...mapGetters('batchComments', ['draftsCount']), ...mapGetters(['isNotesFetched', 'getNoteableData']), diffs() { @@ -305,6 +323,32 @@ export default { if (id && id.indexOf('#note') !== 0) { this.setHighlightedRow(id.split('diff-content').pop().slice(1)); } + + if (window.gon?.features?.diffSettingsUsageData) { + if (this.renderTreeList) { + api.trackRedisHllUserEvent(TRACKING_FILE_BROWSER_TREE); + } else { + api.trackRedisHllUserEvent(TRACKING_FILE_BROWSER_LIST); + } + + if (this.diffViewType === INLINE_DIFF_VIEW_TYPE) { + api.trackRedisHllUserEvent(TRACKING_DIFF_VIEW_INLINE); + } else { + api.trackRedisHllUserEvent(TRACKING_DIFF_VIEW_PARALLEL); + } + + if (this.showWhitespace) { + api.trackRedisHllUserEvent(TRACKING_WHITESPACE_SHOW); + } else { + api.trackRedisHllUserEvent(TRACKING_WHITESPACE_HIDE); + } + + if (this.viewDiffsFileByFile) { + api.trackRedisHllUserEvent(TRACKING_SINGLE_FILE_MODE); + } else { + api.trackRedisHllUserEvent(TRACKING_MULTIPLE_FILES_MODE); + } + } }, beforeCreate() { diffsApp.instrument(); @@ -523,17 +567,41 @@ export default { <commit-widget v-if="commit" :commit="commit" :collapsible="false" /> <div v-if="isBatchLoading" class="loading"><gl-loading-icon size="lg" /></div> <template v-else-if="renderDiffFiles"> - <diff-file - v-for="(file, index) in diffs" - :key="file.newPath" - :file="file" - :reviewed="fileReviews[file.id]" - :is-first-file="index === 0" - :is-last-file="index === diffFilesLength - 1" - :help-page-path="helpPagePath" - :can-current-user-fork="canCurrentUserFork" - :view-diffs-file-by-file="viewDiffsFileByFile" - /> + <dynamic-scroller + v-if="isVirtualScrollingEnabled" + :items="diffs" + :min-item-size="70" + :buffer="1000" + :use-transform="false" + page-mode + > + <template #default="{ item, index, active }"> + <dynamic-scroller-item :item="item" :active="active"> + <diff-file + :file="item" + :reviewed="fileReviews[item.id]" + :is-first-file="index === 0" + :is-last-file="index === diffFilesLength - 1" + :help-page-path="helpPagePath" + :can-current-user-fork="canCurrentUserFork" + :view-diffs-file-by-file="viewDiffsFileByFile" + /> + </dynamic-scroller-item> + </template> + </dynamic-scroller> + <template v-else> + <diff-file + v-for="(file, index) in diffs" + :key="file.new_path" + :file="file" + :reviewed="fileReviews[file.id]" + :is-first-file="index === 0" + :is-last-file="index === diffFilesLength - 1" + :help-page-path="helpPagePath" + :can-current-user-fork="canCurrentUserFork" + :view-diffs-file-by-file="viewDiffsFileByFile" + /> + </template> <div v-if="showFileByFileNavigation" data-testid="file-by-file-navigation" diff --git a/app/assets/javascripts/diffs/components/commit_item.vue b/app/assets/javascripts/diffs/components/commit_item.vue index bc0f2fb0b69..820c64a9502 100644 --- a/app/assets/javascripts/diffs/components/commit_item.vue +++ b/app/assets/javascripts/diffs/components/commit_item.vue @@ -138,7 +138,7 @@ export default { /> </div> <div class="commit-detail flex-list"> - <div class="commit-content qa-commit-content"> + <div class="commit-content" data-qa-selector="commit_content"> <a :href="commit.commit_url" class="commit-row-message item-title" @@ -173,7 +173,7 @@ export default { <pre v-if="commit.description_html" :class="{ 'js-toggle-content': collapsible, 'd-block': !collapsible }" - class="commit-row-description gl-mb-3 text-dark" + class="commit-row-description gl-mb-3 gl-text-body" v-html="commitDescription" ></pre> </div> diff --git a/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue b/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue index 2c249f71091..6c5973b7c28 100644 --- a/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue +++ b/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue @@ -1,11 +1,12 @@ <script> -import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; +import { GlDropdown, GlDropdownItem, GlDropdownDivider } from '@gitlab/ui'; import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; export default { components: { GlDropdown, GlDropdownItem, + GlDropdownDivider, TimeAgo, }, props: { @@ -24,34 +25,38 @@ export default { <template> <gl-dropdown :text="selectedVersionName" data-qa-selector="dropdown_content"> - <gl-dropdown-item - v-for="version in versions" - :key="version.id" - :class="{ - 'is-active': version.selected, - }" - :is-check-item="true" - :is-checked="version.selected" - :href="version.href" - > - <div> - <strong> - {{ version.versionName }} - <template v-if="version.isHead">{{ s__('DiffsCompareBaseBranch|(HEAD)') }}</template> - <template v-else-if="version.isBase">{{ s__('DiffsCompareBaseBranch|(base)') }}</template> - </strong> - </div> - <div> - <small class="commit-sha"> {{ version.short_commit_sha }} </small> - </div> - <div> - <small> - <template v-if="version.commitsText"> - {{ version.commitsText }} - </template> - <time-ago v-if="version.created_at" :time="version.created_at" class="js-timeago" /> - </small> - </div> - </gl-dropdown-item> + <template v-for="version in versions"> + <gl-dropdown-divider v-if="version.addDivider" :key="version.id" /> + <gl-dropdown-item + :key="version.id" + :class="{ + 'is-active': version.selected, + }" + :is-check-item="true" + :is-checked="version.selected" + :href="version.href" + > + <div> + <strong> + {{ version.versionName }} + <template v-if="version.isHead">{{ s__('DiffsCompareBaseBranch|(HEAD)') }}</template> + <template v-else-if="version.isBase">{{ + s__('DiffsCompareBaseBranch|(base)') + }}</template> + </strong> + </div> + <div> + <small class="commit-sha"> {{ version.short_commit_sha }} </small> + </div> + <div> + <small> + <template v-if="version.commitsText"> + {{ version.commitsText }} + </template> + <time-ago v-if="version.created_at" :time="version.created_at" class="js-timeago" /> + </small> + </div> + </gl-dropdown-item> + </template> </gl-dropdown> </template> diff --git a/app/assets/javascripts/diffs/components/compare_versions.vue b/app/assets/javascripts/diffs/components/compare_versions.vue index 7526c5347f7..e2a1f7236c5 100644 --- a/app/assets/javascripts/diffs/components/compare_versions.vue +++ b/app/assets/javascripts/diffs/components/compare_versions.vue @@ -142,7 +142,7 @@ export default { </gl-button-group> </div> <gl-sprintf - v-else-if="hasSourceVersions" + v-else-if="!commit && hasSourceVersions" class="d-flex align-items-center compare-versions-container" :message="s__('MergeRequest|Compare %{target} and %{source}')" > diff --git a/app/assets/javascripts/diffs/components/diff_content.vue b/app/assets/javascripts/diffs/components/diff_content.vue index 663d2bb3cf8..283dbc6031c 100644 --- a/app/assets/javascripts/diffs/components/diff_content.vue +++ b/app/assets/javascripts/diffs/components/diff_content.vue @@ -49,9 +49,7 @@ export default { }, }, computed: { - ...mapState({ - projectPath: (state) => state.diffs.projectPath, - }), + ...mapState('diffs', ['projectPath']), ...mapGetters('diffs', [ 'isInlineView', 'isParallelView', diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index bdbc13a38c4..ce867dbb9e0 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -5,6 +5,7 @@ import { mapActions, mapGetters, mapState } from 'vuex'; import { deprecatedCreateFlash as createFlash } from '~/flash'; import { hasDiff } from '~/helpers/diffs_helper'; import { diffViewerErrors } from '~/ide/constants'; +import { scrollToElement } from '~/lib/utils/common_utils'; import { sprintf } from '~/locale'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import notesEventHub from '../../notes/event_hub'; @@ -82,7 +83,7 @@ export default { computed: { ...mapState('diffs', ['currentDiffFileId', 'codequalityDiff']), ...mapGetters(['isNotesFetched']), - ...mapGetters('diffs', ['getDiffFileDiscussions']), + ...mapGetters('diffs', ['getDiffFileDiscussions', 'isVirtualScrollingEnabled']), viewBlobHref() { return escape(this.file.view_path); }, @@ -148,10 +149,8 @@ export default { return loggedIn && featureOn; }, - hasCodequalityChanges() { - return ( - this.codequalityDiff?.files && this.codequalityDiff?.files[this.file.file_path]?.length > 0 - ); + codequalityDiffForFile() { + return this.codequalityDiff?.files?.[this.file.file_path] || []; }, }, watch: { @@ -235,15 +234,20 @@ export default { eventHub.$emit(event); }); }, - handleToggle() { - const currentCollapsedFlag = this.isCollapsed; + handleToggle({ viaUserInteraction = false } = {}) { + const collapsingNow = !this.isCollapsed; + const contentElement = this.$el.querySelector(`#diff-content-${this.file.file_hash}`); this.setFileCollapsedByUser({ filePath: this.file.file_path, - collapsed: !currentCollapsedFlag, + collapsed: collapsingNow, }); - if (!this.hasDiff && currentCollapsedFlag) { + if (collapsingNow && viaUserInteraction && contentElement) { + scrollToElement(contentElement, { duration: 1 }); + } + + if (!this.hasDiff && !collapsingNow) { this.requestDiff(); } }, @@ -286,6 +290,7 @@ export default { 'is-active': currentDiffFileId === file.file_hash, 'comments-disabled': Boolean(file.brokenSymlink), 'has-body': showBody, + 'is-virtual-scrolling': isVirtualScrollingEnabled, }" :data-path="file.new_path" class="diff-file file-holder gl-border-none" @@ -299,10 +304,10 @@ export default { :add-merge-request-buttons="true" :view-diffs-file-by-file="viewDiffsFileByFile" :show-local-file-reviews="showLocalFileReviews" - :has-codequality-changes="hasCodequalityChanges" + :codequality-diff="codequalityDiffForFile" class="js-file-title file-title gl-border-1 gl-border-solid gl-border-gray-100" :class="hasBodyClasses.header" - @toggleFile="handleToggle" + @toggleFile="handleToggle({ viaUserInteraction: true })" @showForkMessage="showForkMessage" /> diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue index 3b4e21ab61b..676c9a3c7bc 100644 --- a/app/assets/javascripts/diffs/components/diff_file_header.vue +++ b/app/assets/javascripts/diffs/components/diff_file_header.vue @@ -96,10 +96,10 @@ export default { required: false, default: false, }, - hasCodequalityChanges: { - type: Boolean, + codequalityDiff: { + type: Array, required: false, - default: false, + default: () => [], }, }, data() { @@ -333,7 +333,12 @@ export default { data-track-property="diff_copy_file" /> - <code-quality-badge v-if="hasCodequalityChanges" class="gl-mr-2" /> + <code-quality-badge + v-if="codequalityDiff.length" + :file-name="filePath" + :codequality-diff="codequalityDiff" + class="gl-mr-2" + /> <small v-if="isModeChanged" ref="fileMode" class="mr-1"> {{ diffFile.a_mode }} → {{ diffFile.b_mode }} diff --git a/app/assets/javascripts/diffs/components/diff_line_note_form.vue b/app/assets/javascripts/diffs/components/diff_line_note_form.vue index 51da1966630..c907b5dffaf 100644 --- a/app/assets/javascripts/diffs/components/diff_line_note_form.vue +++ b/app/assets/javascripts/diffs/components/diff_line_note_form.vue @@ -207,14 +207,14 @@ export default { </div> <note-form ref="noteForm" - :is-editing="true" + :is-editing="false" :line-code="line.line_code" :line="line" :lines="commentLines" :help-page-path="helpPagePath" :diff-file="diffFile" :show-suggest-popover="showSuggestPopover" - save-button-title="Comment" + :save-button-title="__('Comment')" class="diff-comment-form gl-mt-3" @handleFormUpdateAddToReview="addToReview" @cancelForm="handleCancelCommentForm" diff --git a/app/assets/javascripts/diffs/components/diff_row.vue b/app/assets/javascripts/diffs/components/diff_row.vue index 8d398a2ded4..d4a1a9e0e46 100644 --- a/app/assets/javascripts/diffs/components/diff_row.vue +++ b/app/assets/javascripts/diffs/components/diff_row.vue @@ -204,27 +204,33 @@ export default { <template v-if="line.left && line.left.type !== $options.CONFLICT_MARKER"> <div :class="classNameMapCellLeft" - data-testid="leftLineNumber" + data-testid="left-line-number" class="diff-td diff-line-num" + data-qa-selector="new_diff_line_link" > <template v-if="!isLeftConflictMarker"> <span v-if="shouldRenderCommentButton && !line.hasDiscussionsLeft" v-gl-tooltip - data-testid="leftCommentButton" class="add-diff-note tooltip-wrapper" :title="addCommentTooltipLeft" > - <button - :draggable="glFeatures.dragCommentSelection" + <div + data-testid="left-comment-button" + role="button" + tabindex="0" + :draggable="!line.left.commentsDisabled && glFeatures.dragCommentSelection" type="button" - class="add-diff-note unified-diff-components-diff-note-button note-button js-add-diff-note-button qa-diff-comment" + class="add-diff-note unified-diff-components-diff-note-button note-button js-add-diff-note-button" data-qa-selector="diff_comment_button" :class="{ 'gl-cursor-grab': dragging }" :disabled="line.left.commentsDisabled" - @click="handleCommentButton(line.left)" - @dragstart="onDragStart({ ...line.left, index })" - ></button> + :aria-disabled="line.left.commentsDisabled" + @click="!line.left.commentsDisabled && handleCommentButton(line.left)" + @keydown.enter="!line.left.commentsDisabled && handleCommentButton(line.left)" + @keydown.space="!line.left.commentsDisabled && handleCommentButton(line.left)" + @dragstart="!line.left.commentsDisabled && onDragStart({ ...line.left, index })" + ></div> </span> </template> <a @@ -238,7 +244,7 @@ export default { v-if="line.hasDiscussionsLeft" :discussions="line.left.discussions" :discussions-expanded="line.left.discussionsExpanded" - data-testid="leftDiscussions" + data-testid="left-discussions" @toggleLineDiscussions=" toggleLineDiscussions({ lineCode: line.left.line_code, @@ -268,7 +274,7 @@ export default { :key="line.left.line_code" :class="[parallelViewLeftLineType, { parallel: !inline }]" class="diff-td line_content with-coverage left-side" - data-testid="leftContent" + data-testid="left-content" @mousedown="handleParallelLineMouseDown" > <strong v-if="isLeftConflictMarker">{{ conflictText(line.left) }}</strong> @@ -277,7 +283,7 @@ export default { </template> <template v-else-if="!inline || (line.left && line.left.type === $options.CONFLICT_MARKER)"> <div - data-testid="leftEmptyCell" + data-testid="left-empty-cell" class="diff-td diff-line-num old_line empty-cell" :class="emptyCellLeftClassMap" > @@ -313,19 +319,24 @@ export default { <span v-if="shouldRenderCommentButton && !line.hasDiscussionsRight" v-gl-tooltip - data-testid="rightCommentButton" class="add-diff-note tooltip-wrapper" :title="addCommentTooltipRight" > - <button - :draggable="glFeatures.dragCommentSelection" + <div + data-testid="right-comment-button" + role="button" + tabindex="0" + :draggable="!line.right.commentsDisabled && glFeatures.dragCommentSelection" type="button" - class="add-diff-note unified-diff-components-diff-note-button note-button js-add-diff-note-button qa-diff-comment" + class="add-diff-note unified-diff-components-diff-note-button note-button js-add-diff-note-button" :class="{ 'gl-cursor-grab': dragging }" :disabled="line.right.commentsDisabled" - @click="handleCommentButton(line.right)" - @dragstart="onDragStart({ ...line.right, index })" - ></button> + :aria-disabled="line.right.commentsDisabled" + @click="!line.right.commentsDisabled && handleCommentButton(line.right)" + @keydown.enter="!line.right.commentsDisabled && handleCommentButton(line.right)" + @keydown.space="!line.right.commentsDisabled && handleCommentButton(line.right)" + @dragstart="!line.right.commentsDisabled && onDragStart({ ...line.right, index })" + ></div> </span> </template> <a @@ -339,7 +350,7 @@ export default { v-if="line.hasDiscussionsRight" :discussions="line.right.discussions" :discussions-expanded="line.right.discussionsExpanded" - data-testid="rightDiscussions" + data-testid="right-discussions" @toggleLineDiscussions=" toggleLineDiscussions({ lineCode: line.right.line_code, @@ -381,7 +392,7 @@ export default { </template> <template v-else> <div - data-testid="rightEmptyCell" + data-testid="right-empty-cell" class="diff-td diff-line-num old_line empty-cell" :class="emptyCellRightClassMap" ></div> diff --git a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue index 25403b1547e..f903fef72b7 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue @@ -177,7 +177,6 @@ export default { <a v-if="line.new_line" ref="lineNumberRefNew" - data-qa-selector="new_diff_line_link" :data-linenumber="line.new_line" :href="line.lineHref" @click="setHighlightedRow(line.lineCode)" diff --git a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue index 96946d0fd88..2d33926c8aa 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue @@ -193,7 +193,7 @@ export default { v-show="shouldShowCommentButtonLeft" ref="addDiffNoteButtonLeft" type="button" - class="add-diff-note note-button js-add-diff-note-button qa-diff-comment" + class="add-diff-note note-button js-add-diff-note-button" :disabled="line.left.commentsDisabled" :aria-label="addCommentTooltipLeft" @click="handleCommentButton(line.left)" @@ -251,7 +251,7 @@ export default { v-show="shouldShowCommentButtonRight" ref="addDiffNoteButtonRight" type="button" - class="add-diff-note note-button js-add-diff-note-button qa-diff-comment" + class="add-diff-note note-button js-add-diff-note-button" :disabled="line.right.commentsDisabled" :aria-label="addCommentTooltipRight" @click="handleCommentButton(line.right)" diff --git a/app/assets/javascripts/diffs/constants.js b/app/assets/javascripts/diffs/constants.js index 0163f508fea..f0e15983336 100644 --- a/app/assets/javascripts/diffs/constants.js +++ b/app/assets/javascripts/diffs/constants.js @@ -114,3 +114,20 @@ export const CONFLICT_THEIR = 'conflict_their'; export const CONFLICT_MARKER = 'conflict_marker'; export const CONFLICT_MARKER_OUR = 'conflict_marker_our'; export const CONFLICT_MARKER_THEIR = 'conflict_marker_their'; + +// Tracking events +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'; + +export const TRACKING_CLICK_FILE_BROWSER_SETTING = 'i_code_review_click_file_browser_setting'; +export const TRACKING_FILE_BROWSER_TREE = 'i_code_review_file_browser_tree_view'; +export const TRACKING_FILE_BROWSER_LIST = 'i_code_review_file_browser_list_view'; + +export const TRACKING_CLICK_WHITESPACE_SETTING = 'i_code_review_click_whitespace_setting'; +export const TRACKING_WHITESPACE_SHOW = 'i_code_review_diff_show_whitespace'; +export const TRACKING_WHITESPACE_HIDE = 'i_code_review_diff_hide_whitespace'; + +export const TRACKING_CLICK_SINGLE_FILE_SETTING = 'i_code_review_click_single_file_mode_setting'; +export const TRACKING_SINGLE_FILE_MODE = 'i_code_review_diff_single_file'; +export const TRACKING_MULTIPLE_FILES_MODE = 'i_code_review_diff_multiple_files'; diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index 428faf693b0..d0730e18228 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -1,5 +1,6 @@ import Cookies from 'js-cookie'; import Vue from 'vue'; +import api from '~/api'; import { deprecatedCreateFlash as createFlash } from '~/flash'; import { diffViewerModes } from '~/ide/constants'; import axios from '~/lib/utils/axios_utils'; @@ -36,6 +37,18 @@ import { DIFF_VIEW_FILE_BY_FILE, DIFF_VIEW_ALL_FILES, DIFF_FILE_BY_FILE_COOKIE_NAME, + 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, } from '../constants'; import eventHub from '../event_hub'; import { isCollapsed } from '../utils/diff_file'; @@ -352,6 +365,11 @@ export const setInlineDiffViewType = ({ commit }) => { Cookies.set(DIFF_VIEW_COOKIE_NAME, INLINE_DIFF_VIEW_TYPE); const url = mergeUrlParams({ view: INLINE_DIFF_VIEW_TYPE }, window.location.href); historyPushState(url); + + if (window.gon?.features?.diffSettingsUsageData) { + api.trackRedisHllUserEvent(TRACKING_CLICK_DIFF_VIEW_SETTING); + api.trackRedisHllUserEvent(TRACKING_DIFF_VIEW_INLINE); + } }; export const setParallelDiffViewType = ({ commit }) => { @@ -360,6 +378,11 @@ export const setParallelDiffViewType = ({ commit }) => { Cookies.set(DIFF_VIEW_COOKIE_NAME, PARALLEL_DIFF_VIEW_TYPE); const url = mergeUrlParams({ view: PARALLEL_DIFF_VIEW_TYPE }, window.location.href); historyPushState(url); + + if (window.gon?.features?.diffSettingsUsageData) { + api.trackRedisHllUserEvent(TRACKING_CLICK_DIFF_VIEW_SETTING); + api.trackRedisHllUserEvent(TRACKING_DIFF_VIEW_PARALLEL); + } }; export const showCommentForm = ({ commit }, { lineCode, fileHash }) => { @@ -527,6 +550,16 @@ export const setRenderTreeList = ({ commit }, renderTreeList) => { 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 (renderTreeList) { + api.trackRedisHllUserEvent(TRACKING_FILE_BROWSER_TREE); + } else { + api.trackRedisHllUserEvent(TRACKING_FILE_BROWSER_LIST); + } + } }; export const setShowWhitespace = ({ commit }, { showWhitespace, pushState = false }) => { @@ -540,6 +573,16 @@ export const setShowWhitespace = ({ commit }, { showWhitespace, pushState = fals } notesEventHub.$emit('refetchDiffData'); + + if (window.gon?.features?.diffSettingsUsageData) { + api.trackRedisHllUserEvent(TRACKING_CLICK_WHITESPACE_SETTING); + + if (showWhitespace) { + api.trackRedisHllUserEvent(TRACKING_WHITESPACE_SHOW); + } else { + api.trackRedisHllUserEvent(TRACKING_WHITESPACE_HIDE); + } + } }; export const toggleFileFinder = ({ commit }, visible) => { @@ -754,6 +797,16 @@ export const setFileByFile = ({ state, commit }, { fileByFile }) => { commit(types.SET_FILE_BY_FILE, fileByFile); Cookies.set(DIFF_FILE_BY_FILE_COOKIE_NAME, fileViewMode); + if (window.gon?.features?.diffSettingsUsageData) { + api.trackRedisHllUserEvent(TRACKING_CLICK_SINGLE_FILE_SETTING); + + if (fileByFile) { + api.trackRedisHllUserEvent(TRACKING_SINGLE_FILE_MODE); + } else { + api.trackRedisHllUserEvent(TRACKING_MULTIPLE_FILES_MODE); + } + } + return axios .put(state.endpointUpdateUser, { view_diffs_file_by_file: fileByFile, diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js index dec3f87b03e..0a9623c13a3 100644 --- a/app/assets/javascripts/diffs/store/getters.js +++ b/app/assets/javascripts/diffs/store/getters.js @@ -170,3 +170,6 @@ export function suggestionCommitMessage(state, _, rootState) { }, }); } + +export const isVirtualScrollingEnabled = (state) => + !state.viewDiffsFileByFile && window.gon?.features?.diffsVirtualScrolling; diff --git a/app/assets/javascripts/diffs/store/getters_versions_dropdowns.js b/app/assets/javascripts/diffs/store/getters_versions_dropdowns.js index 01811e60caa..673ec821b58 100644 --- a/app/assets/javascripts/diffs/store/getters_versions_dropdowns.js +++ b/app/assets/javascripts/diffs/store/getters_versions_dropdowns.js @@ -7,6 +7,9 @@ export const selectedTargetIndex = (state) => export const selectedSourceIndex = (state) => state.mergeRequestDiff.version_index; +export const selectedContextCommitsDiffs = (state) => + state.contextCommitsDiff && state.contextCommitsDiff.showing_context_commits_diff; + 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 @@ -58,7 +61,7 @@ export const diffCompareDropdownTargetVersions = (state, getters) => { export const diffCompareDropdownSourceVersions = (state, getters) => { // Appended properties here are to make the compare_dropdown_layout easier to reason about - return state.mergeRequestDiffs.map((v, i) => { + const versions = state.mergeRequestDiffs.map((v, i) => { const isLatestVersion = i === 0; return { @@ -69,7 +72,20 @@ export const diffCompareDropdownSourceVersions = (state, getters) => { versionName: isLatestVersion ? __('latest version') : sprintf(__(`version %{versionIndex}`), { versionIndex: v.version_index }), - selected: v.version_index === getters.selectedSourceIndex, + selected: + v.version_index === getters.selectedSourceIndex && !getters.selectedContextCommitsDiffs, }; }); + + const { contextCommitsDiff } = state; + if (contextCommitsDiff) { + versions.push({ + href: contextCommitsDiff.diffs_path, + commitsText: n__(`%d commit`, `%d commits`, contextCommitsDiff.commits_count), + versionName: __('previously merged commits'), + selected: getters.selectedContextCommitsDiffs, + addDivider: state.mergeRequestDiffs.length > 0, + }); + } + return versions; }; diff --git a/app/assets/javascripts/diffs/utils/diff_file.js b/app/assets/javascripts/diffs/utils/diff_file.js index 7e6fde320d2..a96c1207a04 100644 --- a/app/assets/javascripts/diffs/utils/diff_file.js +++ b/app/assets/javascripts/diffs/utils/diff_file.js @@ -1,4 +1,5 @@ import { truncateSha } from '~/lib/utils/text_utility'; +import { uuids } from '~/lib/utils/uuids'; import { DIFF_FILE_SYMLINK_MODE, @@ -7,7 +8,6 @@ import { DIFF_FILE_AUTOMATIC_COLLAPSE, } from '../constants'; import { getDerivedMergeRequestInformation } from './merge_request'; -import { uuids } from './uuids'; function fileSymlinkInformation(file, fileList) { const duplicates = fileList.filter((iteratedFile) => iteratedFile.file_hash === file.file_hash); diff --git a/app/assets/javascripts/diffs/utils/uuids.js b/app/assets/javascripts/diffs/utils/uuids.js deleted file mode 100644 index 98fe4bf9664..00000000000 --- a/app/assets/javascripts/diffs/utils/uuids.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @module uuids - */ - -/** - * A string or number representing a start state for a random generator - * @typedef {(Number|String)} Seed - */ -/** - * A UUIDv4 string in the format <code>Hex{8}-Hex{4}-4Hex{3}-[89ab]Hex{3}-Hex{12}</code> - * @typedef {String} UUIDv4 - */ - -import { MersenneTwister } from 'fast-mersenne-twister'; -import { isString } from 'lodash'; -import stringHash from 'string-hash'; -import { v4 } from 'uuid'; - -function getSeed(seeds) { - return seeds.reduce((seedling, seed, i) => { - let thisSeed = 0; - - if (Number.isInteger(seed)) { - thisSeed = seed; - } else if (isString(seed)) { - thisSeed = stringHash(seed); - } - - return seedling + (seeds.length - i) * thisSeed; - }, 0); -} - -function getPseudoRandomNumberGenerator(...seeds) { - let seedNumber; - - if (seeds.length) { - seedNumber = getSeed(seeds); - } else { - seedNumber = Math.floor(Math.random() * 10 ** 15); - } - - return new MersenneTwister(seedNumber); -} - -function randomValuesForUuid(prng) { - const randomValues = []; - - for (let i = 0; i <= 3; i += 1) { - const buffer = new ArrayBuffer(4); - const view = new DataView(buffer); - - view.setUint32(0, prng.randomNumber()); - - randomValues.push(view.getUint8(0), view.getUint8(1), view.getUint8(2), view.getUint8(3)); - } - - return randomValues; -} - -/** - * Get an array of UUIDv4s - * @param {Object} [options={}] - * @param {Seed[]} [options.seeds=[]] - A list of mixed strings or numbers to seed the UUIDv4 generator - * @param {Number} [options.count=1] - A total number of UUIDv4s to generate - * @returns {UUIDv4[]} An array of UUIDv4s - */ -export function uuids({ seeds = [], count = 1 } = {}) { - const rng = getPseudoRandomNumberGenerator(...seeds); - return ( - // Create an array the same size as the number of UUIDs requested - Array(count) - .fill(0) - // Replace each slot in the array with a UUID which needs 16 (pseudo)random values to generate - .map(() => v4({ random: randomValuesForUuid(rng) })) - ); -} |