Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/diffs')
-rw-r--r--app/assets/javascripts/diffs/components/app.vue11
-rw-r--r--app/assets/javascripts/diffs/components/diff_content.vue3
-rw-r--r--app/assets/javascripts/diffs/components/diff_expansion_cell.vue6
-rw-r--r--app/assets/javascripts/diffs/components/diff_file.vue6
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue11
-rw-r--r--app/assets/javascripts/diffs/components/diff_row.vue42
-rw-r--r--app/assets/javascripts/diffs/components/diff_stats.vue53
-rw-r--r--app/assets/javascripts/diffs/components/diff_view.vue12
-rw-r--r--app/assets/javascripts/diffs/components/settings_dropdown.vue19
-rw-r--r--app/assets/javascripts/diffs/constants.js4
-rw-r--r--app/assets/javascripts/diffs/i18n.js1
-rw-r--r--app/assets/javascripts/diffs/index.js21
-rw-r--r--app/assets/javascripts/diffs/store/actions.js39
-rw-r--r--app/assets/javascripts/diffs/store/getters.js10
-rw-r--r--app/assets/javascripts/diffs/store/modules/diff_state.js11
-rw-r--r--app/assets/javascripts/diffs/store/modules/index.js2
-rw-r--r--app/assets/javascripts/diffs/store/utils.js116
-rw-r--r--app/assets/javascripts/diffs/utils/diff_file.js36
-rw-r--r--app/assets/javascripts/diffs/utils/workers.js107
-rw-r--r--app/assets/javascripts/diffs/workers/tree_worker.js2
20 files changed, 326 insertions, 186 deletions
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index 6a3f5993a22..61946d345e3 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -12,7 +12,7 @@ import {
MR_COMMITS_NEXT_COMMIT,
MR_COMMITS_PREVIOUS_COMMIT,
} from '~/behaviors/shortcuts/keybindings';
-import { deprecatedCreateFlash as createFlash } from '~/flash';
+import createFlash from '~/flash';
import { isSingleViewStyle } from '~/helpers/diffs_helper';
import { getParameterByName, parseBoolean } from '~/lib/utils/common_utils';
import { updateHistory } from '~/lib/utils/url_utility';
@@ -181,7 +181,6 @@ export default {
plainDiffPath: (state) => state.diffs.plainDiffPath,
emailPatchPath: (state) => state.diffs.emailPatchPath,
retrievingBatches: (state) => state.diffs.retrievingBatches,
- codequalityDiff: (state) => state.diffs.codequalityDiff,
}),
...mapState('diffs', [
'showTreeList',
@@ -425,7 +424,9 @@ export default {
if (toggleTree) this.setTreeDisplay();
})
.catch(() => {
- createFlash(__('Something went wrong on our end. Please try again!'));
+ createFlash({
+ message: __('Something went wrong on our end. Please try again!'),
+ });
});
this.fetchDiffFilesBatch()
@@ -438,7 +439,9 @@ export default {
this.setDiscussions();
})
.catch(() => {
- createFlash(__('Something went wrong on our end. Please try again!'));
+ createFlash({
+ message: __('Something went wrong on our end. Please try again!'),
+ });
});
if (this.endpointCoverage) {
diff --git a/app/assets/javascripts/diffs/components/diff_content.vue b/app/assets/javascripts/diffs/components/diff_content.vue
index 283dbc6031c..cb74c7dc7cd 100644
--- a/app/assets/javascripts/diffs/components/diff_content.vue
+++ b/app/assets/javascripts/diffs/components/diff_content.vue
@@ -1,6 +1,7 @@
<script>
import { GlLoadingIcon } from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex';
+import { mapInline, mapParallel } from 'ee_else_ce/diffs/components/diff_row_utils';
import DiffFileDrafts from '~/batch_comments/components/diff_file_drafts.vue';
import draftCommentsMixin from '~/diffs/mixins/draft_comments';
import { diffViewerModes } from '~/ide/constants';
@@ -15,7 +16,6 @@ import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_
import { IMAGE_DIFF_POSITION_TYPE } from '../constants';
import { getDiffMode } from '../store/utils';
import DiffDiscussions from './diff_discussions.vue';
-import { mapInline, mapParallel } from './diff_row_utils';
import DiffView from './diff_view.vue';
import ImageDiffOverlay from './image_diff_overlay.vue';
import InlineDiffView from './inline_diff_view.vue';
@@ -55,6 +55,7 @@ export default {
'isParallelView',
'getCommentFormForDiffFile',
'diffLines',
+ 'fileLineCodequality',
]),
...mapGetters(['getNoteableData', 'noteableType', 'getUserData']),
diffMode() {
diff --git a/app/assets/javascripts/diffs/components/diff_expansion_cell.vue b/app/assets/javascripts/diffs/components/diff_expansion_cell.vue
index 67900af8789..edff2e67b20 100644
--- a/app/assets/javascripts/diffs/components/diff_expansion_cell.vue
+++ b/app/assets/javascripts/diffs/components/diff_expansion_cell.vue
@@ -1,7 +1,7 @@
<script>
import { GlIcon } from '@gitlab/ui';
import { mapState, mapActions } from 'vuex';
-import { deprecatedCreateFlash as createFlash } from '~/flash';
+import createFlash from '~/flash';
import { s__, sprintf } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { UNFOLD_COUNT, INLINE_DIFF_VIEW_TYPE, INLINE_DIFF_LINES_KEY } from '../constants';
@@ -95,7 +95,9 @@ export default {
this.isRequesting = false;
})
.catch(() => {
- createFlash(s__('Diffs|Something went wrong while fetching diff lines.'));
+ createFlash({
+ message: s__('Diffs|Something went wrong while fetching diff lines.'),
+ });
this.isRequesting = false;
});
},
diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue
index ce867dbb9e0..ed8455f0c1c 100644
--- a/app/assets/javascripts/diffs/components/diff_file.vue
+++ b/app/assets/javascripts/diffs/components/diff_file.vue
@@ -2,7 +2,7 @@
import { GlButton, GlLoadingIcon, GlSafeHtmlDirective as SafeHtml, GlSprintf } from '@gitlab/ui';
import { escape } from 'lodash';
import { mapActions, mapGetters, mapState } from 'vuex';
-import { deprecatedCreateFlash as createFlash } from '~/flash';
+import createFlash from '~/flash';
import { hasDiff } from '~/helpers/diffs_helper';
import { diffViewerErrors } from '~/ide/constants';
import { scrollToElement } from '~/lib/utils/common_utils';
@@ -270,7 +270,9 @@ export default {
})
.catch(() => {
this.isLoadingCollapsedDiff = false;
- createFlash(this.$options.i18n.genericError);
+ createFlash({
+ message: this.$options.i18n.genericError,
+ });
});
},
showForkMessage() {
diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue
index 676c9a3c7bc..45c7fe35f03 100644
--- a/app/assets/javascripts/diffs/components/diff_file_header.vue
+++ b/app/assets/javascripts/diffs/components/diff_file_header.vue
@@ -202,6 +202,9 @@ export default {
externalUrlLabel() {
return sprintf(__('View on %{url}'), { url: this.diffFile.formatted_external_url });
},
+ showCodequalityBadge() {
+ return this.codequalityDiff?.length > 0 && !this.glFeatures.codequalityMrDiffAnnotations;
+ },
},
methods: {
...mapActions('diffs', [
@@ -334,7 +337,7 @@ export default {
/>
<code-quality-badge
- v-if="codequalityDiff.length"
+ v-if="showCodequalityBadge"
:file-name="filePath"
:codequality-diff="codequalityDiff"
class="gl-mr-2"
@@ -351,7 +354,11 @@ export default {
v-if="!diffFile.submodule && addMergeRequestButtons"
class="file-actions d-flex align-items-center gl-ml-auto gl-align-self-start"
>
- <diff-stats :added-lines="diffFile.added_lines" :removed-lines="diffFile.removed_lines" />
+ <diff-stats
+ :diff-file="diffFile"
+ :added-lines="diffFile.added_lines"
+ :removed-lines="diffFile.removed_lines"
+ />
<gl-form-checkbox
v-if="isReviewable && showLocalFileReviews"
v-gl-tooltip.hover
diff --git a/app/assets/javascripts/diffs/components/diff_row.vue b/app/assets/javascripts/diffs/components/diff_row.vue
index d4a1a9e0e46..37dd7941b2e 100644
--- a/app/assets/javascripts/diffs/components/diff_row.vue
+++ b/app/assets/javascripts/diffs/components/diff_row.vue
@@ -24,6 +24,8 @@ import * as utils from './diff_row_utils';
export default {
components: {
DiffGutterAvatars,
+ CodeQualityGutterIcon: () =>
+ import('ee_component/diffs/components/code_quality_gutter_icon.vue'),
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -89,6 +91,20 @@ export default {
if (!this.line.right) return {};
return this.fileLineCoverage(this.filePath, this.line.right.new_line);
},
+ showCodequalityLeft() {
+ return (
+ this.glFeatures.codequalityMrDiffAnnotations &&
+ this.inline &&
+ this.line.left?.codequality?.length > 0
+ );
+ },
+ showCodequalityRight() {
+ return (
+ this.glFeatures.codequalityMrDiffAnnotations &&
+ !this.inline &&
+ this.line.right?.codequality?.length > 0
+ );
+ },
classNameMapCellLeft() {
return utils.classNameMapCell({
line: this.line.left,
@@ -269,6 +285,13 @@ export default {
:class="[...parallelViewLeftLineType, coverageStateLeft.class]"
class="diff-td line-coverage left-side"
></div>
+ <div class="diff-td line-codequality left-side" :class="[...parallelViewLeftLineType]">
+ <code-quality-gutter-icon
+ v-if="showCodequalityLeft"
+ :file-path="filePath"
+ :codequality="line.left.codequality"
+ />
+ </div>
<div
:id="line.left.line_code"
:key="line.left.line_code"
@@ -299,6 +322,11 @@ export default {
:class="emptyCellLeftClassMap"
></div>
<div
+ v-if="inline"
+ class="diff-td line-codequality left-side empty-cell"
+ :class="emptyCellLeftClassMap"
+ ></div>
+ <div
class="diff-td line_content with-coverage left-side empty-cell"
:class="[emptyCellLeftClassMap, { parallel: !inline }]"
></div>
@@ -371,6 +399,16 @@ export default {
class="diff-td line-coverage right-side"
></div>
<div
+ class="diff-td line-codequality right-side"
+ :class="[line.right.type, { hll: isHighlighted, hll: isCommented }]"
+ >
+ <code-quality-gutter-icon
+ v-if="showCodequalityRight"
+ :file-path="filePath"
+ :codequality="line.right.codequality"
+ />
+ </div>
+ <div
:id="line.right.line_code"
:key="line.right.rich_text"
:class="[
@@ -406,6 +444,10 @@ export default {
:class="emptyCellRightClassMap"
></div>
<div
+ class="diff-td line-codequality right-side empty-cell"
+ :class="emptyCellRightClassMap"
+ ></div>
+ <div
class="diff-td line_content with-coverage right-side empty-cell"
:class="[emptyCellRightClassMap, { parallel: !inline }]"
></div>
diff --git a/app/assets/javascripts/diffs/components/diff_stats.vue b/app/assets/javascripts/diffs/components/diff_stats.vue
index 0303700f42a..05d4fbe7c20 100644
--- a/app/assets/javascripts/diffs/components/diff_stats.vue
+++ b/app/assets/javascripts/diffs/components/diff_stats.vue
@@ -2,10 +2,16 @@
import { GlIcon } from '@gitlab/ui';
import { isNumber } from 'lodash';
import { n__ } from '~/locale';
+import { isNotDiffable, stats } from '../utils/diff_file';
export default {
components: { GlIcon },
props: {
+ diffFile: {
+ type: Object,
+ required: false,
+ default: () => null,
+ },
addedLines: {
type: Number,
required: true,
@@ -33,6 +39,12 @@ export default {
hasDiffFiles() {
return isNumber(this.diffFilesLength) && this.diffFilesLength >= 0;
},
+ notDiffable() {
+ return isNotDiffable(this.diffFile);
+ },
+ fileStats() {
+ return stats(this.diffFile);
+ },
},
};
</script>
@@ -41,27 +53,32 @@ export default {
<div
class="diff-stats"
:class="{
- 'is-compare-versions-header d-none d-lg-inline-flex': isCompareVersionsHeader,
- 'd-none d-sm-inline-flex': !isCompareVersionsHeader,
+ 'is-compare-versions-header gl-display-none gl-lg-display-inline-flex': isCompareVersionsHeader,
+ 'gl-display-none gl-sm-display-inline-flex': !isCompareVersionsHeader,
}"
>
- <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>
- </div>
- <div
- class="diff-stats-group cgreen d-flex align-items-center"
- :class="{ bold: isCompareVersionsHeader }"
- >
- <span>+</span>
- <span class="js-file-addition-line">{{ addedLines }}</span>
+ <div v-if="notDiffable" :class="fileStats.classes">
+ {{ fileStats.text }}
</div>
- <div
- class="diff-stats-group cred d-flex align-items-center"
- :class="{ bold: isCompareVersionsHeader }"
- >
- <span>-</span>
- <span class="js-file-deletion-line">{{ removedLines }}</span>
+ <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>
+ </div>
+ <div
+ class="diff-stats-group gl-text-green-600 gl-display-flex gl-align-items-center"
+ :class="{ bold: isCompareVersionsHeader }"
+ >
+ <span>+</span>
+ <span data-testid="js-file-addition-line">{{ addedLines }}</span>
+ </div>
+ <div
+ class="diff-stats-group gl-text-red-500 gl-display-flex gl-align-items-center"
+ :class="{ bold: isCompareVersionsHeader }"
+ >
+ <span>-</span>
+ <span data-testid="js-file-deletion-line">{{ removedLines }}</span>
+ </div>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/diffs/components/diff_view.vue b/app/assets/javascripts/diffs/components/diff_view.vue
index 43cfa22073f..a2a6ebaeedf 100644
--- a/app/assets/javascripts/diffs/components/diff_view.vue
+++ b/app/assets/javascripts/diffs/components/diff_view.vue
@@ -3,6 +3,7 @@ import { mapGetters, mapState, mapActions } from 'vuex';
import DraftNote from '~/batch_comments/components/draft_note.vue';
import draftCommentsMixin from '~/diffs/mixins/draft_comments';
import { getCommentedLines } from '~/notes/components/multiline_comment_utils';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import DiffCommentCell from './diff_comment_cell.vue';
import DiffExpansionCell from './diff_expansion_cell.vue';
import DiffRow from './diff_row.vue';
@@ -14,7 +15,7 @@ export default {
DiffCommentCell,
DraftNote,
},
- mixins: [draftCommentsMixin],
+ mixins: [draftCommentsMixin, glFeatureFlagsMixin()],
props: {
diffFile: {
type: Object,
@@ -43,6 +44,7 @@ export default {
},
computed: {
...mapGetters('diffs', ['commitId']),
+ ...mapState('diffs', ['codequalityDiff']),
...mapState({
selectedCommentPosition: ({ notes }) => notes.selectedCommentPosition,
selectedCommentPositionHover: ({ notes }) => notes.selectedCommentPositionHover,
@@ -56,6 +58,12 @@ export default {
this.diffLines,
);
},
+ hasCodequalityChanges() {
+ return (
+ this.glFeatures.codequalityMrDiffAnnotations &&
+ this.codequalityDiff?.files?.[this.diffFile.file_path]?.length > 0
+ );
+ },
},
methods: {
...mapActions(['setSelectedCommentPosition']),
@@ -98,7 +106,7 @@ export default {
<template>
<div
- :class="[$options.userColorScheme, { inline }]"
+ :class="[$options.userColorScheme, { inline, 'with-codequality': hasCodequalityChanges }]"
:data-commit-id="commitId"
class="diff-grid diff-table code diff-wrap-lines js-syntax-highlight text-file"
>
diff --git a/app/assets/javascripts/diffs/components/settings_dropdown.vue b/app/assets/javascripts/diffs/components/settings_dropdown.vue
index 879922f86a2..178f93b651e 100644
--- a/app/assets/javascripts/diffs/components/settings_dropdown.vue
+++ b/app/assets/javascripts/diffs/components/settings_dropdown.vue
@@ -1,10 +1,19 @@
<script>
-import { GlButtonGroup, GlButton, GlDropdown, GlFormCheckbox } from '@gitlab/ui';
+import {
+ GlButtonGroup,
+ GlButton,
+ GlDropdown,
+ GlFormCheckbox,
+ GlTooltipDirective,
+} from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex';
import { SETTINGS_DROPDOWN } from '../i18n';
export default {
i18n: SETTINGS_DROPDOWN,
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
components: {
GlButtonGroup,
GlButton,
@@ -27,7 +36,7 @@ export default {
this.setFileByFile({ fileByFile: !this.viewDiffsFileByFile });
},
toggleWhitespace(updatedSetting) {
- this.setShowWhitespace({ showWhitespace: updatedSetting, pushState: true });
+ this.setShowWhitespace({ showWhitespace: updatedSetting });
},
},
};
@@ -35,9 +44,13 @@ export default {
<template>
<gl-dropdown
+ v-gl-tooltip
icon="settings"
- :text="__('Diff view settings')"
+ :title="$options.i18n.preferences"
+ :text="$options.i18n.preferences"
:text-sr-only="true"
+ :aria-label="$options.i18n.preferences"
+ :header-text="$options.i18n.preferences"
toggle-class="js-show-diff-settings"
right
>
diff --git a/app/assets/javascripts/diffs/constants.js b/app/assets/javascripts/diffs/constants.js
index f0e15983336..d1e02fbc598 100644
--- a/app/assets/javascripts/diffs/constants.js
+++ b/app/assets/javascripts/diffs/constants.js
@@ -1,7 +1,3 @@
-// The backend actually uses "hide_whitespace" while the frontend
-// uses "show whitspace" so these values are opposite what you might expect
-export const NO_SHOW_WHITESPACE = '1';
-export const SHOW_WHITESPACE = '0';
export const INLINE_DIFF_VIEW_TYPE = 'inline';
export const PARALLEL_DIFF_VIEW_TYPE = 'parallel';
export const MATCH_LINE_TYPE = 'match';
diff --git a/app/assets/javascripts/diffs/i18n.js b/app/assets/javascripts/diffs/i18n.js
index b2354af1eec..a45fd92d0a9 100644
--- a/app/assets/javascripts/diffs/i18n.js
+++ b/app/assets/javascripts/diffs/i18n.js
@@ -23,4 +23,5 @@ export const DIFF_FILE = {
export const SETTINGS_DROPDOWN = {
whitespace: __('Show whitespace changes'),
fileByFile: __('Show one file at a time'),
+ preferences: __('Preferences'),
};
diff --git a/app/assets/javascripts/diffs/index.js b/app/assets/javascripts/diffs/index.js
index 5a8862c2b70..0ab72749760 100644
--- a/app/assets/javascripts/diffs/index.js
+++ b/app/assets/javascripts/diffs/index.js
@@ -98,10 +98,23 @@ export default function initDiffsApp(store) {
this.setRenderTreeList(renderTreeList);
- // Set whitespace default as per user preferences unless cookie is already set
- if (!Cookies.get(DIFF_WHITESPACE_COOKIE_NAME)) {
- const hideWhitespace = this.showWhitespaceDefault ? '0' : '1';
- this.setShowWhitespace({ showWhitespace: hideWhitespace !== '1' });
+ // NOTE: A "true" or "checked" value for `showWhitespace` is '0' not '1'.
+ // Check for cookie and save that setting for future use.
+ // Then delete the cookie as we are phasing it out and using the database as SSOT.
+ // NOTE: This can/should be removed later
+ if (Cookies.get(DIFF_WHITESPACE_COOKIE_NAME)) {
+ const hideWhitespace = Cookies.get(DIFF_WHITESPACE_COOKIE_NAME);
+ this.setShowWhitespace({
+ url: this.endpointUpdateUser,
+ showWhitespace: hideWhitespace !== '1',
+ });
+ Cookies.remove(DIFF_WHITESPACE_COOKIE_NAME);
+ } else {
+ // This is only to set the the user preference in Vuex for use later
+ this.setShowWhitespace({
+ showWhitespace: this.showWhitespaceDefault,
+ updateDatabase: false,
+ });
}
},
methods: {
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js
index d0730e18228..2e94f147086 100644
--- a/app/assets/javascripts/diffs/store/actions.js
+++ b/app/assets/javascripts/diffs/store/actions.js
@@ -1,7 +1,7 @@
import Cookies from 'js-cookie';
import Vue from 'vue';
import api from '~/api';
-import { deprecatedCreateFlash as createFlash } from '~/flash';
+import createFlash from '~/flash';
import { diffViewerModes } from '~/ide/constants';
import axios from '~/lib/utils/axios_utils';
import { handleLocationHash, historyPushState, scrollToElement } from '~/lib/utils/common_utils';
@@ -26,9 +26,6 @@ import {
START_RENDERING_INDEX,
INLINE_DIFF_LINES_KEY,
DIFFS_PER_PAGE,
- DIFF_WHITESPACE_COOKIE_NAME,
- SHOW_WHITESPACE,
- NO_SHOW_WHITESPACE,
DIFF_FILE_MANUAL_COLLAPSE,
DIFF_FILE_AUTOMATIC_COLLAPSE,
EVT_PERF_MARK_FILE_TREE_START,
@@ -240,7 +237,10 @@ export const fetchCoverageFiles = ({ commit, state }) => {
coveragePoll.stop();
}
},
- errorCallback: () => createFlash(__('Something went wrong on our end. Please try again!')),
+ errorCallback: () =>
+ createFlash({
+ message: __('Something went wrong on our end. Please try again!'),
+ }),
});
coveragePoll.makeRequest();
@@ -504,7 +504,11 @@ export const saveDiffDiscussion = ({ state, dispatch }, { note, formData }) => {
.then((discussion) => dispatch('assignDiscussionsToDiff', [discussion]))
.then(() => dispatch('updateResolvableDiscussionsCounts', null, { root: true }))
.then(() => dispatch('closeDiffFileCommentForm', formData.diffFile.file_hash))
- .catch(() => createFlash(s__('MergeRequests|Saving the comment failed')));
+ .catch(() =>
+ createFlash({
+ message: s__('MergeRequests|Saving the comment failed'),
+ }),
+ );
};
export const toggleTreeOpen = ({ commit }, path) => {
@@ -562,16 +566,15 @@ export const setRenderTreeList = ({ commit }, renderTreeList) => {
}
};
-export const setShowWhitespace = ({ commit }, { showWhitespace, pushState = false }) => {
- commit(types.SET_SHOW_WHITESPACE, showWhitespace);
- const w = showWhitespace ? SHOW_WHITESPACE : NO_SHOW_WHITESPACE;
-
- Cookies.set(DIFF_WHITESPACE_COOKIE_NAME, w);
-
- if (pushState) {
- historyPushState(mergeUrlParams({ w }, window.location.href));
+export const setShowWhitespace = async (
+ { state, commit },
+ { url, showWhitespace, updateDatabase = true },
+) => {
+ if (updateDatabase) {
+ await axios.put(url || state.endpointUpdateUser, { show_whitespace_in_diffs: showWhitespace });
}
+ commit(types.SET_SHOW_WHITESPACE, showWhitespace);
notesEventHub.$emit('refetchDiffData');
if (window.gon?.features?.diffSettingsUsageData) {
@@ -595,7 +598,9 @@ export const cacheTreeListWidth = (_, size) => {
export const receiveFullDiffError = ({ commit }, filePath) => {
commit(types.RECEIVE_FULL_DIFF_ERROR, filePath);
- createFlash(s__('MergeRequest|Error loading full diff. Please try again.'));
+ createFlash({
+ message: s__('MergeRequest|Error loading full diff. Please try again.'),
+ });
};
export const setExpandedDiffLines = ({ commit }, { file, data }) => {
@@ -727,7 +732,9 @@ export const setSuggestPopoverDismissed = ({ commit, state }) =>
commit(types.SET_SHOW_SUGGEST_POPOVER);
})
.catch(() => {
- createFlash(s__('MergeRequest|Error dismissing suggestion popover. Please try again.'));
+ createFlash({
+ message: s__('MergeRequest|Error dismissing suggestion popover. Please try again.'),
+ });
});
export function changeCurrentCommit({ dispatch, commit, state }, { commitId }) {
diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js
index 0a9623c13a3..a536db5c417 100644
--- a/app/assets/javascripts/diffs/store/getters.js
+++ b/app/assets/javascripts/diffs/store/getters.js
@@ -1,3 +1,4 @@
+import { getParameterValues } from '~/lib/utils/url_utility';
import { __, n__ } from '~/locale';
import {
PARALLEL_DIFF_VIEW_TYPE,
@@ -135,6 +136,11 @@ export const fileLineCoverage = (state) => (file, line) => {
return {};
};
+// This function is overwritten for the inline codequality feature in EE
+export const fileLineCodequality = () => () => {
+ return null;
+};
+
/**
* Returns index of a currently selected diff in diffFiles
* @returns {number}
@@ -172,4 +178,6 @@ export function suggestionCommitMessage(state, _, rootState) {
}
export const isVirtualScrollingEnabled = (state) =>
- !state.viewDiffsFileByFile && window.gon?.features?.diffsVirtualScrolling;
+ !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 1674d3d3b5a..348dd452698 100644
--- a/app/assets/javascripts/diffs/store/modules/diff_state.js
+++ b/app/assets/javascripts/diffs/store/modules/diff_state.js
@@ -1,20 +1,13 @@
import Cookies from 'js-cookie';
import { getParameterValues } from '~/lib/utils/url_utility';
-import {
- INLINE_DIFF_VIEW_TYPE,
- DIFF_VIEW_COOKIE_NAME,
- DIFF_WHITESPACE_COOKIE_NAME,
-} from '../../constants';
+import { INLINE_DIFF_VIEW_TYPE, DIFF_VIEW_COOKIE_NAME } from '../../constants';
import { fileByFile } from '../../utils/preferences';
-import { getDefaultWhitespace } from '../utils';
const getViewTypeFromQueryString = () => getParameterValues('view')[0];
const viewTypeFromCookie = Cookies.get(DIFF_VIEW_COOKIE_NAME);
const defaultViewType = INLINE_DIFF_VIEW_TYPE;
-const whiteSpaceFromQueryString = getParameterValues('w')[0];
-const whiteSpaceFromCookie = Cookies.get(DIFF_WHITESPACE_COOKIE_NAME);
export default () => ({
isLoading: true,
@@ -42,7 +35,7 @@ export default () => ({
commentForms: [],
highlightedRow: null,
renderTreeList: true,
- showWhitespace: getDefaultWhitespace(whiteSpaceFromQueryString, whiteSpaceFromCookie),
+ showWhitespace: true,
viewDiffsFileByFile: fileByFile(),
fileFinderVisible: false,
dismissEndpoint: '',
diff --git a/app/assets/javascripts/diffs/store/modules/index.js b/app/assets/javascripts/diffs/store/modules/index.js
index 03d11e60745..169502a957b 100644
--- a/app/assets/javascripts/diffs/store/modules/index.js
+++ b/app/assets/javascripts/diffs/store/modules/index.js
@@ -1,7 +1,7 @@
import * as actions from 'ee_else_ce/diffs/store/actions';
+import * as getters from 'ee_else_ce/diffs/store/getters';
import createState from 'ee_else_ce/diffs/store/modules/diff_state';
import mutations from 'ee_else_ce/diffs/store/mutations';
-import * as getters from '../getters';
export default () => ({
namespaced: true,
diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js
index 7fa51b9ddea..75d2cf43b94 100644
--- a/app/assets/javascripts/diffs/store/utils.js
+++ b/app/assets/javascripts/diffs/store/utils.js
@@ -1,6 +1,5 @@
import { property, isEqual } from 'lodash';
import { diffModes, diffViewerModes } from '~/ide/constants';
-import { truncatePathMiddleToLength } from '~/lib/utils/text_utility';
import {
LINE_POSITION_LEFT,
LINE_POSITION_RIGHT,
@@ -11,10 +10,7 @@ import {
OLD_LINE_TYPE,
MATCH_LINE_TYPE,
LINES_TO_BE_RENDERED_DIRECTLY,
- TREE_TYPE,
INLINE_DIFF_LINES_KEY,
- SHOW_WHITESPACE,
- NO_SHOW_WHITESPACE,
CONFLICT_OUR,
CONFLICT_THEIR,
CONFLICT_MARKER,
@@ -485,111 +481,6 @@ export function isDiscussionApplicableToLine({ discussion, diffPosition, latestD
return latestDiff && discussion.active && line_code === discussion.line_code;
}
-export const getLowestSingleFolder = (folder) => {
- const getFolder = (blob, start = []) =>
- blob.tree.reduce(
- (acc, file) => {
- const shouldGetFolder = file.tree.length === 1 && file.tree[0].type === TREE_TYPE;
- const currentFileTypeTree = file.type === TREE_TYPE;
- const path = shouldGetFolder || currentFileTypeTree ? acc.path.concat(file.name) : acc.path;
- const tree = shouldGetFolder || currentFileTypeTree ? acc.tree.concat(file) : acc.tree;
-
- if (shouldGetFolder) {
- const firstFolder = getFolder(file);
-
- path.push(...firstFolder.path);
- tree.push(...firstFolder.tree);
- }
-
- return {
- ...acc,
- path,
- tree,
- };
- },
- { path: start, tree: [] },
- );
- const { path, tree } = getFolder(folder, [folder.name]);
-
- return {
- path: truncatePathMiddleToLength(path.join('/'), 40),
- treeAcc: tree.length ? tree[tree.length - 1].tree : null,
- };
-};
-
-export const flattenTree = (tree) => {
- const flatten = (blobTree) =>
- blobTree.reduce((acc, file) => {
- const blob = file;
- let treeToFlatten = blob.tree;
-
- if (file.type === TREE_TYPE && file.tree.length === 1) {
- const { treeAcc, path } = getLowestSingleFolder(file);
-
- if (treeAcc) {
- blob.name = path;
- treeToFlatten = flatten(treeAcc);
- }
- }
-
- blob.tree = flatten(treeToFlatten);
-
- return acc.concat(blob);
- }, []);
-
- return flatten(tree);
-};
-
-export const generateTreeList = (files) => {
- const { treeEntries, tree } = files.reduce(
- (acc, file) => {
- const split = file.new_path.split('/');
-
- split.forEach((name, i) => {
- const parent = acc.treeEntries[split.slice(0, i).join('/')];
- const path = `${parent ? `${parent.path}/` : ''}${name}`;
-
- if (!acc.treeEntries[path]) {
- const type = path === file.new_path ? 'blob' : 'tree';
- acc.treeEntries[path] = {
- key: path,
- path,
- name,
- type,
- tree: [],
- };
-
- const entry = acc.treeEntries[path];
-
- if (type === 'blob') {
- Object.assign(entry, {
- changed: true,
- tempFile: file.new_file,
- deleted: file.deleted_file,
- fileHash: file.file_hash,
- addedLines: file.added_lines,
- removedLines: file.removed_lines,
- parentPath: parent ? `${parent.path}/` : '/',
- submodule: file.submodule,
- });
- } else {
- Object.assign(entry, {
- opened: true,
- });
- }
-
- (parent ? parent.tree : acc.tree).push(entry);
- }
- });
-
- return acc;
- },
- { treeEntries: {}, tree: [] },
- );
-
- return { treeEntries, tree: flattenTree(tree) };
-};
-
export const getDiffMode = (diffFile) => {
const diffModeKey = Object.keys(diffModes).find((key) => diffFile[`${key}_file`]);
return (
@@ -666,10 +557,3 @@ export const allDiscussionWrappersExpanded = (diff) => {
return discussionsExpanded;
};
-
-export const getDefaultWhitespace = (queryString, cookie) => {
- // Querystring should override stored cookie value
- if (queryString) return queryString === SHOW_WHITESPACE;
- if (cookie === NO_SHOW_WHITESPACE) return false;
- return true;
-};
diff --git a/app/assets/javascripts/diffs/utils/diff_file.js b/app/assets/javascripts/diffs/utils/diff_file.js
index a96c1207a04..54dcf70c491 100644
--- a/app/assets/javascripts/diffs/utils/diff_file.js
+++ b/app/assets/javascripts/diffs/utils/diff_file.js
@@ -1,3 +1,5 @@
+import { diffViewerModes as viewerModes } from '~/ide/constants';
+import { changeInPercent, numberToHumanSize } from '~/lib/utils/number_utils';
import { truncateSha } from '~/lib/utils/text_utility';
import { uuids } from '~/lib/utils/uuids';
@@ -46,6 +48,8 @@ function identifier(file) {
})[0];
}
+export const isNotDiffable = (file) => file?.viewer?.name === viewerModes.not_diffable;
+
export function prepareRawDiffFile({ file, allFiles, meta = false }) {
const additionalProperties = {
brokenSymlink: fileSymlinkInformation(file, allFiles),
@@ -84,3 +88,35 @@ export function isCollapsed(file) {
export function getShortShaFromFile(file) {
return file.content_sha ? truncateSha(String(file.content_sha)) : null;
}
+
+export function stats(file) {
+ let valid = false;
+ let classes = '';
+ let sign = '';
+ let text = '';
+ let percent = 0;
+ let diff = 0;
+
+ if (file) {
+ percent = changeInPercent(file.old_size, file.new_size);
+ diff = file.new_size - file.old_size;
+ sign = diff >= 0 ? '+' : '';
+ text = `${sign}${numberToHumanSize(diff)} (${sign}${percent}%)`;
+ valid = true;
+
+ if (diff > 0) {
+ classes = 'gl-text-green-600';
+ } else if (diff < 0) {
+ classes = 'gl-text-red-500';
+ }
+ }
+
+ return {
+ changed: diff,
+ text,
+ percent,
+ classes,
+ sign,
+ valid,
+ };
+}
diff --git a/app/assets/javascripts/diffs/utils/workers.js b/app/assets/javascripts/diffs/utils/workers.js
new file mode 100644
index 00000000000..985e75d1a17
--- /dev/null
+++ b/app/assets/javascripts/diffs/utils/workers.js
@@ -0,0 +1,107 @@
+import { truncatePathMiddleToLength } from '~/lib/utils/text_utility';
+import { TREE_TYPE } from '../constants';
+
+export const getLowestSingleFolder = (folder) => {
+ const getFolder = (blob, start = []) =>
+ blob.tree.reduce(
+ (acc, file) => {
+ const shouldGetFolder = file.tree.length === 1 && file.tree[0].type === TREE_TYPE;
+ const currentFileTypeTree = file.type === TREE_TYPE;
+ const path = shouldGetFolder || currentFileTypeTree ? acc.path.concat(file.name) : acc.path;
+ const tree = shouldGetFolder || currentFileTypeTree ? acc.tree.concat(file) : acc.tree;
+
+ if (shouldGetFolder) {
+ const firstFolder = getFolder(file);
+
+ path.push(...firstFolder.path);
+ tree.push(...firstFolder.tree);
+ }
+
+ return {
+ ...acc,
+ path,
+ tree,
+ };
+ },
+ { path: start, tree: [] },
+ );
+ const { path, tree } = getFolder(folder, [folder.name]);
+
+ return {
+ path: truncatePathMiddleToLength(path.join('/'), 40),
+ treeAcc: tree.length ? tree[tree.length - 1].tree : null,
+ };
+};
+
+export const flattenTree = (tree) => {
+ const flatten = (blobTree) =>
+ blobTree.reduce((acc, file) => {
+ const blob = file;
+ let treeToFlatten = blob.tree;
+
+ if (file.type === TREE_TYPE && file.tree.length === 1) {
+ const { treeAcc, path } = getLowestSingleFolder(file);
+
+ if (treeAcc) {
+ blob.name = path;
+ treeToFlatten = flatten(treeAcc);
+ }
+ }
+
+ blob.tree = flatten(treeToFlatten);
+
+ return acc.concat(blob);
+ }, []);
+
+ return flatten(tree);
+};
+
+export const generateTreeList = (files) => {
+ const { treeEntries, tree } = files.reduce(
+ (acc, file) => {
+ const split = file.new_path.split('/');
+
+ split.forEach((name, i) => {
+ const parent = acc.treeEntries[split.slice(0, i).join('/')];
+ const path = `${parent ? `${parent.path}/` : ''}${name}`;
+
+ if (!acc.treeEntries[path]) {
+ const type = path === file.new_path ? 'blob' : 'tree';
+ acc.treeEntries[path] = {
+ key: path,
+ path,
+ name,
+ type,
+ tree: [],
+ };
+
+ const entry = acc.treeEntries[path];
+
+ if (type === 'blob') {
+ Object.assign(entry, {
+ changed: true,
+ tempFile: file.new_file,
+ deleted: file.deleted_file,
+ fileHash: file.file_hash,
+ addedLines: file.added_lines,
+ removedLines: file.removed_lines,
+ parentPath: parent ? `${parent.path}/` : '/',
+ submodule: file.submodule,
+ });
+ } else {
+ Object.assign(entry, {
+ opened: true,
+ });
+ }
+
+ (parent ? parent.tree : acc.tree).push(entry);
+ }
+ });
+
+ return acc;
+ },
+ { treeEntries: {}, tree: [] },
+ );
+
+ return { treeEntries, tree: flattenTree(tree) };
+};
diff --git a/app/assets/javascripts/diffs/workers/tree_worker.js b/app/assets/javascripts/diffs/workers/tree_worker.js
index 2fa1934439e..6d1bc78ba1c 100644
--- a/app/assets/javascripts/diffs/workers/tree_worker.js
+++ b/app/assets/javascripts/diffs/workers/tree_worker.js
@@ -1,5 +1,5 @@
import { sortTree } from '~/ide/stores/utils';
-import { generateTreeList } from '../store/utils';
+import { generateTreeList } from '../utils/workers';
// eslint-disable-next-line no-restricted-globals
self.addEventListener('message', (e) => {