summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/diffs
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-05-19 15:44:42 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-05-19 15:44:42 +0000
commit4555e1b21c365ed8303ffb7a3325d773c9b8bf31 (patch)
tree5423a1c7516cffe36384133ade12572cf709398d /app/assets/javascripts/diffs
parente570267f2f6b326480d284e0164a6464ba4081bc (diff)
downloadgitlab-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')
-rw-r--r--app/assets/javascripts/diffs/components/app.vue96
-rw-r--r--app/assets/javascripts/diffs/components/commit_item.vue4
-rw-r--r--app/assets/javascripts/diffs/components/compare_dropdown_layout.vue65
-rw-r--r--app/assets/javascripts/diffs/components/compare_versions.vue2
-rw-r--r--app/assets/javascripts/diffs/components/diff_content.vue4
-rw-r--r--app/assets/javascripts/diffs/components/diff_file.vue27
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue13
-rw-r--r--app/assets/javascripts/diffs/components/diff_line_note_form.vue4
-rw-r--r--app/assets/javascripts/diffs/components/diff_row.vue51
-rw-r--r--app/assets/javascripts/diffs/components/inline_diff_table_row.vue1
-rw-r--r--app/assets/javascripts/diffs/components/parallel_diff_table_row.vue4
-rw-r--r--app/assets/javascripts/diffs/constants.js17
-rw-r--r--app/assets/javascripts/diffs/store/actions.js53
-rw-r--r--app/assets/javascripts/diffs/store/getters.js3
-rw-r--r--app/assets/javascripts/diffs/store/getters_versions_dropdowns.js20
-rw-r--r--app/assets/javascripts/diffs/utils/diff_file.js2
-rw-r--r--app/assets/javascripts/diffs/utils/uuids.js76
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) }))
- );
-}