diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-16 18:25:58 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-16 18:25:58 +0000 |
commit | a5f4bba440d7f9ea47046a0a561d49adf0a1e6d4 (patch) | |
tree | fb69158581673816a8cd895f9d352dcb3c678b1e /app/assets/javascripts/diffs | |
parent | d16b2e8639e99961de6ddc93909f3bb5c1445ba1 (diff) | |
download | gitlab-ce-a5f4bba440d7f9ea47046a0a561d49adf0a1e6d4.tar.gz |
Add latest changes from gitlab-org/gitlab@14-0-stable-eev14.0.0-rc42
Diffstat (limited to 'app/assets/javascripts/diffs')
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) => { |