diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-17 11:59:07 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-17 11:59:07 +0000 |
commit | 8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca (patch) | |
tree | 544930fb309b30317ae9797a9683768705d664c4 /app/assets/javascripts/diffs | |
parent | 4b1de649d0168371549608993deac953eb692019 (diff) | |
download | gitlab-ce-8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca.tar.gz |
Add latest changes from gitlab-org/gitlab@13-7-stable-eev13.7.0-rc42
Diffstat (limited to 'app/assets/javascripts/diffs')
25 files changed, 378 insertions, 546 deletions
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 9d8d184a3f6..7827c78b658 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -1,6 +1,7 @@ <script> import { mapState, mapGetters, mapActions } from 'vuex'; import { GlLoadingIcon, GlPagination, GlSprintf } from '@gitlab/ui'; +import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils'; import Mousetrap from 'mousetrap'; import { __ } from '~/locale'; import { getParameterByName, parseBoolean } from '~/lib/utils/common_utils'; @@ -9,7 +10,10 @@ import PanelResizer from '~/vue_shared/components/panel_resizer.vue'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { isSingleViewStyle } from '~/helpers/diffs_helper'; import { updateHistory } from '~/lib/utils/url_utility'; -import eventHub from '../../notes/event_hub'; + +import notesEventHub from '../../notes/event_hub'; +import eventHub from '../event_hub'; + import CompareVersions from './compare_versions.vue'; import DiffFile from './diff_file.vue'; import NoChanges from './no_changes.vue'; @@ -21,6 +25,7 @@ import MergeConflictWarning from './merge_conflict_warning.vue'; import CollapsedFilesWarning from './collapsed_files_warning.vue'; import { diffsApp } from '../utils/performance'; +import { fileByFile } from '../utils/preferences'; import { TREE_LIST_WIDTH_STORAGE_KEY, @@ -33,6 +38,7 @@ import { ALERT_OVERFLOW_HIDDEN, ALERT_MERGE_CONFLICT, ALERT_COLLAPSED_FILES, + EVT_VIEW_FILE_BY_FILE, } from '../constants'; export default { @@ -113,7 +119,7 @@ export default { required: false, default: false, }, - viewDiffsFileByFile: { + fileByFileUserPreference: { type: Boolean, required: false, default: false, @@ -153,6 +159,7 @@ export default { 'conflictResolutionPath', 'canMerge', 'hasConflicts', + 'viewDiffsFileByFile', ]), ...mapGetters('diffs', ['whichCollapsedTypes', 'isParallelView', 'currentDiffIndex']), ...mapGetters(['isNotesFetched', 'getNoteableData']), @@ -230,9 +237,6 @@ export default { } }, diffViewType() { - if (!this.glFeatures.unifiedDiffLines && (this.needsReload() || this.needsFirstLoad())) { - this.refetchDiffData(); - } this.adjustView(); }, shouldShow() { @@ -256,7 +260,7 @@ export default { projectPath: this.projectPath, dismissEndpoint: this.dismissEndpoint, showSuggestPopover: this.showSuggestPopover, - viewDiffsFileByFile: this.viewDiffsFileByFile, + viewDiffsFileByFile: fileByFile(this.fileByFileUserPreference), }); if (this.shouldShow) { @@ -279,9 +283,8 @@ export default { }, created() { this.adjustView(); + this.subscribeToEvents(); - eventHub.$once('fetchDiffData', this.fetchData); - eventHub.$on('refetchDiffData', this.refetchDiffData); this.CENTERED_LIMITED_CONTAINER_CLASSES = CENTERED_LIMITED_CONTAINER_CLASSES; this.unwatchDiscussions = this.$watch( @@ -301,9 +304,7 @@ export default { }, beforeDestroy() { diffsApp.deinstrument(); - - eventHub.$off('fetchDiffData', this.fetchData); - eventHub.$off('refetchDiffData', this.refetchDiffData); + this.unsubscribeFromEvents(); this.removeEventListeners(); }, methods: { @@ -319,9 +320,23 @@ export default { 'setHighlightedRow', 'cacheTreeListWidth', 'scrollToFile', - 'toggleShowTreeList', + 'setShowTreeList', 'navigateToDiffFileIndex', + 'setFileByFile', ]), + subscribeToEvents() { + notesEventHub.$once('fetchDiffData', this.fetchData); + notesEventHub.$on('refetchDiffData', this.refetchDiffData); + eventHub.$on(EVT_VIEW_FILE_BY_FILE, this.fileByFileListener); + }, + unsubscribeFromEvents() { + eventHub.$off(EVT_VIEW_FILE_BY_FILE, this.fileByFileListener); + notesEventHub.$off('refetchDiffData', this.refetchDiffData); + notesEventHub.$off('fetchDiffData', this.fetchData); + }, + fileByFileListener({ setting } = {}) { + this.setFileByFile({ fileByFile: setting }); + }, navigateToDiffFileNumber(number) { this.navigateToDiffFileIndex(number - 1); }, @@ -346,7 +361,7 @@ export default { this.fetchDiffFilesMeta() .then(({ real_size }) => { this.diffFilesLength = parseInt(real_size, 10); - if (toggleTree) this.hideTreeListIfJustOneFile(); + if (toggleTree) this.setTreeDisplay(); this.startDiffRendering(); }) @@ -356,6 +371,7 @@ export default { this.fetchDiffFilesBatch() .then(() => { + if (toggleTree) this.setTreeDisplay(); // Guarantee the discussions are assigned after the batch finishes. // Just watching the length of the discussions or the diff files // isn't enough, because with split diff loading, neither will @@ -372,7 +388,7 @@ export default { } if (!this.isNotesFetched) { - eventHub.$emit('fetchNotesData'); + notesEventHub.$emit('fetchNotesData'); } }, setDiscussions() { @@ -425,12 +441,17 @@ export default { this.scrollToFile(this.diffFiles[targetIndex].file_path); } }, - hideTreeListIfJustOneFile() { + setTreeDisplay() { const storedTreeShow = localStorage.getItem(MR_TREE_SHOW_KEY); + let showTreeList = true; - if ((storedTreeShow === null && this.diffFiles.length <= 1) || storedTreeShow === 'false') { - this.toggleShowTreeList(false); + if (storedTreeShow !== null) { + showTreeList = parseBoolean(storedTreeShow); + } else if (!bp.isDesktop() || (!this.isBatchLoading && this.diffFiles.length <= 1)) { + showTreeList = false; } + + return this.setShowTreeList({ showTreeList, saving: false }); }, }, minTreeWidth: MIN_TREE_WIDTH, @@ -521,6 +542,7 @@ export default { <template #total>{{ diffFiles.length }}</template> </gl-sprintf> </div> + <gl-loading-icon v-else-if="retrievingBatches" size="lg" /> </template> <no-changes v-else :changes-empty-state-illustration="changesEmptyStateIllustration" /> </div> diff --git a/app/assets/javascripts/diffs/components/commit_item.vue b/app/assets/javascripts/diffs/components/commit_item.vue index 1b747fb7f20..a548354f257 100644 --- a/app/assets/javascripts/diffs/components/commit_item.vue +++ b/app/assets/javascripts/diffs/components/commit_item.vue @@ -136,7 +136,12 @@ export default { class="d-inline-flex mb-2" /> <gl-button-group class="gl-ml-4 gl-mb-4" data-testid="commit-sha-group"> - <gl-button label class="gl-font-monospace" v-text="commit.short_id" /> + <gl-button + label + class="gl-font-monospace" + data-testid="commit-sha-short-id" + v-text="commit.short_id" + /> <clipboard-button :text="commit.id" :title="__('Copy commit SHA')" diff --git a/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue b/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue index adef5d94624..da34a7ee19b 100644 --- a/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue +++ b/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue @@ -1,10 +1,11 @@ <script> -import { GlIcon } from '@gitlab/ui'; +import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; export default { components: { - GlIcon, + GlDropdown, + GlDropdownItem, TimeAgo, }, props: { @@ -22,57 +23,35 @@ export default { </script> <template> - <span class="dropdown inline"> - <a - class="dropdown-menu-toggle btn btn-default w-100" - data-toggle="dropdown" - aria-expanded="false" + <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" > - <span> {{ selectedVersionName }} </span> - <gl-icon :size="12" name="angle-down" class="position-absolute" /> - </a> - <div class="dropdown-menu dropdown-select dropdown-menu-selectable"> - <div class="dropdown-content" data-qa-selector="dropdown_content"> - <ul> - <li v-for="version in versions" :key="version.id"> - <a :class="{ 'is-active': 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> - </a> - </li> - </ul> + <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> - </span> + <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> + </gl-dropdown> </template> - -<style> -.dropdown { - min-width: 0; - max-height: 170px; -} -</style> diff --git a/app/assets/javascripts/diffs/components/compare_versions.vue b/app/assets/javascripts/diffs/components/compare_versions.vue index 700d5ec86c8..f3cc359a679 100644 --- a/app/assets/javascripts/diffs/components/compare_versions.vue +++ b/app/assets/javascripts/diffs/components/compare_versions.vue @@ -65,11 +65,7 @@ export default { polyfillSticky(this.$el); }, methods: { - ...mapActions('diffs', [ - 'setInlineDiffViewType', - 'setParallelDiffViewType', - 'toggleShowTreeList', - ]), + ...mapActions('diffs', ['setInlineDiffViewType', 'setParallelDiffViewType', 'setShowTreeList']), expandAllFiles() { eventHub.$emit(EVT_EXPAND_ALL_FILES); }, @@ -92,7 +88,7 @@ export default { class="gl-mr-3 js-toggle-tree-list" :title="toggleFileBrowserTitle" :selected="showTreeList" - @click="toggleShowTreeList" + @click="setShowTreeList({ showTreeList: !showTreeList })" /> <gl-sprintf v-if="showDropdowns" diff --git a/app/assets/javascripts/diffs/components/diff_content.vue b/app/assets/javascripts/diffs/components/diff_content.vue index 401064fb18f..f938ea368d8 100644 --- a/app/assets/javascripts/diffs/components/diff_content.vue +++ b/app/assets/javascripts/diffs/components/diff_content.vue @@ -87,7 +87,7 @@ export default { return this.getUserData; }, mappedLines() { - if (this.glFeatures.unifiedDiffLines && this.glFeatures.unifiedDiffComponents) { + if (this.glFeatures.unifiedDiffComponents) { return this.diffLines(this.diffFile, true).map(mapParallel(this)) || []; } @@ -95,9 +95,7 @@ export default { if (this.isInlineView) { return this.diffFile.highlighted_diff_lines.map(mapInline(this)); } - return this.glFeatures.unifiedDiffLines - ? this.diffLines(this.diffFile).map(mapParallel(this)) - : this.diffFile.parallel_diff_lines.map(mapParallel(this)) || []; + return this.diffLines(this.diffFile).map(mapParallel(this)); }, }, updated() { @@ -129,9 +127,7 @@ export default { <template> <div class="diff-content"> <div class="diff-viewer"> - <template - v-if="isTextFile && glFeatures.unifiedDiffLines && glFeatures.unifiedDiffComponents" - > + <template v-if="isTextFile && glFeatures.unifiedDiffComponents"> <diff-view :diff-file="diffFile" :diff-lines="mappedLines" @@ -173,12 +169,16 @@ export default { :a-mode="diffFile.a_mode" :b-mode="diffFile.b_mode" > - <image-diff-overlay - slot="image-overlay" - :discussions="imageDiscussions" - :file-hash="diffFileHash" - :can-comment="getNoteableData.current_user.can_create_note && !diffFile.brokenSymlink" - /> + <template #image-overlay="{ renderedWidth, renderedHeight }"> + <image-diff-overlay + v-if="renderedWidth" + :rendered-width="renderedWidth" + :rendered-height="renderedHeight" + :discussions="imageDiscussions" + :file-hash="diffFileHash" + :can-comment="getNoteableData.current_user.can_create_note && !diffFile.brokenSymlink" + /> + </template> <div v-if="showNotesContainer" class="note-container"> <user-avatar-link v-if="diffFileCommentForm && author" diff --git a/app/assets/javascripts/diffs/components/diff_expansion_cell.vue b/app/assets/javascripts/diffs/components/diff_expansion_cell.vue index 4c49dfb5de9..2401e12e4f6 100644 --- a/app/assets/javascripts/diffs/components/diff_expansion_cell.vue +++ b/app/assets/javascripts/diffs/components/diff_expansion_cell.vue @@ -4,7 +4,7 @@ import { GlIcon } from '@gitlab/ui'; import { deprecatedCreateFlash as 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, PARALLEL_DIFF_VIEW_TYPE } from '../constants'; +import { UNFOLD_COUNT, INLINE_DIFF_VIEW_TYPE, INLINE_DIFF_LINES_KEY } from '../constants'; import * as utils from '../store/utils'; const EXPAND_ALL = 0; @@ -14,7 +14,6 @@ const EXPAND_DOWN = 2; const lineNumberByViewType = (viewType, diffLine) => { const numberGetters = { [INLINE_DIFF_VIEW_TYPE]: line => line?.new_line, - [PARALLEL_DIFF_VIEW_TYPE]: line => (line?.right || line?.left)?.new_line, }; const numberGetter = numberGetters[viewType]; return numberGetter && numberGetter(diffLine); @@ -57,9 +56,6 @@ export default { }, computed: { ...mapState({ - diffViewType(state) { - return this.glFeatures.unifiedDiffLines ? INLINE_DIFF_VIEW_TYPE : state.diffs.diffViewType; - }, diffFiles: state => state.diffs.diffFiles, }), canExpandUp() { @@ -77,16 +73,14 @@ export default { ...mapActions('diffs', ['loadMoreLines']), getPrevLineNumber(oldLineNumber, newLineNumber) { const diffFile = utils.findDiffFile(this.diffFiles, this.fileHash); - const lines = { - [INLINE_DIFF_VIEW_TYPE]: diffFile.highlighted_diff_lines, - [PARALLEL_DIFF_VIEW_TYPE]: diffFile.parallel_diff_lines, - }; - const index = utils.getPreviousLineIndex(this.diffViewType, diffFile, { + const index = utils.getPreviousLineIndex(INLINE_DIFF_VIEW_TYPE, diffFile, { oldLineNumber, newLineNumber, }); - return lineNumberByViewType(this.diffViewType, lines[this.diffViewType][index - 2]) || 0; + return ( + lineNumberByViewType(INLINE_DIFF_VIEW_TYPE, diffFile[INLINE_DIFF_LINES_KEY][index - 2]) || 0 + ); }, callLoadMoreLines( endpoint, @@ -113,7 +107,7 @@ export default { this.isRequesting = true; const endpoint = this.contextLinesPath; const { fileHash } = this; - const view = this.diffViewType; + const view = INLINE_DIFF_VIEW_TYPE; const oldLineNumber = this.line.meta_data.old_pos || 0; const newLineNumber = this.line.meta_data.new_pos || 0; const offset = newLineNumber - oldLineNumber; @@ -232,11 +226,11 @@ export default { class="gl-mx-2 gl-cursor-pointer js-unfold-down gl-display-inline-block gl-py-4" @click="handleExpandLines(EXPAND_DOWN)" > - <gl-icon :size="12" name="expand-down" aria-hidden="true" /> + <gl-icon :size="12" name="expand-down" /> <span>{{ $options.i18n.showMore }}</span> </a> <a class="gl-mx-2 cursor-pointer js-unfold-all" @click="handleExpandLines()"> - <gl-icon :size="12" name="expand" aria-hidden="true" /> + <gl-icon :size="12" name="expand" /> <span>{{ $options.i18n.showAll }}</span> </a> <a @@ -244,7 +238,7 @@ export default { class="gl-mx-2 gl-cursor-pointer js-unfold gl-display-inline-block gl-py-4" @click="handleExpandLines(EXPAND_UP)" > - <gl-icon :size="12" name="expand-up" aria-hidden="true" /> + <gl-icon :size="12" name="expand-up" /> <span>{{ $options.i18n.showMore }}</span> </a> </div> diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index 32191d7e309..ed94cabe124 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -10,7 +10,7 @@ import notesEventHub from '../../notes/event_hub'; import DiffFileHeader from './diff_file_header.vue'; import DiffContent from './diff_content.vue'; import { diffViewerErrors } from '~/ide/constants'; -import { collapsedType, isCollapsed } from '../diff_file'; +import { collapsedType, isCollapsed } from '../utils/diff_file'; import { DIFF_FILE_AUTOMATIC_COLLAPSE, DIFF_FILE_MANUAL_COLLAPSE, diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue index 0d99a2e8a60..53d1383b82e 100644 --- a/app/assets/javascripts/diffs/components/diff_file_header.vue +++ b/app/assets/javascripts/diffs/components/diff_file_header.vue @@ -19,7 +19,7 @@ import { __, s__, sprintf } from '~/locale'; import { diffViewerModes } from '~/ide/constants'; import DiffStats from './diff_stats.vue'; import { scrollToElement } from '~/lib/utils/common_utils'; -import { isCollapsed } from '../diff_file'; +import { isCollapsed } from '../utils/diff_file'; import { DIFF_FILE_HEADER } from '../i18n'; export default { @@ -221,7 +221,6 @@ export default { ref="collapseIcon" :name="collapseIcon" :size="16" - aria-hidden="true" class="diff-toggle-caret gl-mr-2" @click.stop="handleToggleFile" /> diff --git a/app/assets/javascripts/diffs/components/diff_file_row.vue b/app/assets/javascripts/diffs/components/diff_file_row.vue index 3888eb781fb..6c5d9170c9e 100644 --- a/app/assets/javascripts/diffs/components/diff_file_row.vue +++ b/app/assets/javascripts/diffs/components/diff_file_row.vue @@ -41,10 +41,6 @@ export default { return !this.hideFileStats && this.file.type === 'blob'; }, fileClasses() { - if (!this.glFeatures.highlightCurrentDiffRow) { - return ''; - } - return this.file.type === 'blob' && !this.viewedFiles[this.file.fileHash] ? 'gl-font-weight-bold' : ''; 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 55f5a736cdf..172a2bdde7d 100644 --- a/app/assets/javascripts/diffs/components/diff_line_note_form.vue +++ b/app/assets/javascripts/diffs/components/diff_line_note_form.vue @@ -7,7 +7,7 @@ import noteForm from '../../notes/components/note_form.vue'; import MultilineCommentForm from '../../notes/components/multiline_comment_form.vue'; import autosave from '../../notes/mixins/autosave'; import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; -import { DIFF_NOTE_TYPE, PARALLEL_DIFF_VIEW_TYPE } from '../constants'; +import { DIFF_NOTE_TYPE, INLINE_DIFF_LINES_KEY, PARALLEL_DIFF_VIEW_TYPE } from '../constants'; import { commentLineOptions, formatLineRange, @@ -102,13 +102,13 @@ export default { }; const getDiffLines = () => { if (this.diffViewType === PARALLEL_DIFF_VIEW_TYPE) { - return (this.glFeatures.unifiedDiffLines - ? this.diffLines(this.diffFile) - : this.diffFile.parallel_diff_lines - ).reduce(combineSides, []); + return this.diffLines(this.diffFile, this.glFeatures.unifiedDiffComponents).reduce( + combineSides, + [], + ); } - return this.diffFile.highlighted_diff_lines; + return this.diffFile[INLINE_DIFF_LINES_KEY]; }; const side = this.line.type === 'new' ? 'right' : 'left'; const lines = getDiffLines(); diff --git a/app/assets/javascripts/diffs/components/diff_row.vue b/app/assets/javascripts/diffs/components/diff_row.vue index 77a97c67f3b..c0719e2a7d9 100644 --- a/app/assets/javascripts/diffs/components/diff_row.vue +++ b/app/assets/javascripts/diffs/components/diff_row.vue @@ -157,10 +157,10 @@ export default { " /> </div> - <div :class="classNameMapCellLeft" class="diff-td diff-line-num old_line"> + <div v-if="inline" :class="classNameMapCellLeft" class="diff-td diff-line-num old_line"> <a - v-if="line.left.old_line" - :data-linenumber="line.left.old_line" + v-if="line.left.new_line" + :data-linenumber="line.left.new_line" :href="line.lineHrefOld" @click="setHighlightedRow(line.lineCode)" > @@ -179,21 +179,14 @@ export default { </template> <template v-else> <div data-testid="leftEmptyCell" class="diff-td diff-line-num old_line empty-cell"></div> - <div class="diff-td diff-line-num old_line empty-cell"></div> + <div v-if="inline" class="diff-td diff-line-num old_line empty-cell"></div> <div class="diff-td line-coverage left-side empty-cell"></div> <div class="diff-td line_content with-coverage parallel left-side empty-cell"></div> </template> </div> - <div - v-if="!inline || (line.right && Boolean(line.right.type))" - class="diff-grid-right right-side" - > + <div v-if="!inline" class="diff-grid-right right-side"> <template v-if="line.right"> - <div - :class="classNameMapCellRight" - data-testid="rightLineNumber" - class="diff-td diff-line-num new_line" - > + <div :class="classNameMapCellRight" class="diff-td diff-line-num new_line"> <span v-if="shouldRenderCommentButton" v-gl-tooltip @@ -231,15 +224,6 @@ export default { " /> </div> - <div :class="classNameMapCellRight" class="diff-td diff-line-num new_line"> - <a - v-if="line.right.new_line" - :data-linenumber="line.right.new_line" - :href="line.lineHrefNew" - @click="setHighlightedRow(line.lineCode)" - > - </a> - </div> <div v-gl-tooltip.hover :title="coverageState.text" diff --git a/app/assets/javascripts/diffs/components/image_diff_overlay.vue b/app/assets/javascripts/diffs/components/image_diff_overlay.vue index 3956c2fab49..6a1e0d8cbd6 100644 --- a/app/assets/javascripts/diffs/components/image_diff_overlay.vue +++ b/app/assets/javascripts/diffs/components/image_diff_overlay.vue @@ -4,6 +4,10 @@ import { isArray } from 'lodash'; import imageDiffMixin from 'ee_else_ce/diffs/mixins/image_diff'; import { GlIcon } from '@gitlab/ui'; +function calcPercent(pos, size, renderedSize) { + return (((pos / size) * 100) / ((renderedSize / size) * 100)) * 100; +} + export default { name: 'ImageDiffOverlay', components: { @@ -39,6 +43,14 @@ export default { required: false, default: true, }, + renderedWidth: { + type: Number, + required: true, + }, + renderedHeight: { + type: Number, + required: true, + }, }, computed: { ...mapGetters('diffs', ['getDiffFileByHash', 'getCommentFormForDiffFile']), @@ -59,33 +71,33 @@ export default { }, getPositionForObject(meta) { const { x, y, width, height } = meta; - const imageWidth = this.getImageDimensions().width; - const imageHeight = this.getImageDimensions().height; - const widthRatio = imageWidth / width; - const heightRatio = imageHeight / height; return { - x: Math.round(x * widthRatio), - y: Math.round(y * heightRatio), + x: (x / width) * 100, + y: (y / height) * 100, }; }, getPosition(discussion) { const { x, y } = this.getPositionForObject(discussion.position); return { - left: `${x}px`, - top: `${y}px`, + left: `${x}%`, + top: `${y}%`, }; }, clickedImage(x, y) { const { width, height } = this.getImageDimensions(); + const xPercent = calcPercent(x, width, this.renderedWidth); + const yPercent = calcPercent(y, height, this.renderedHeight); this.openDiffFileCommentForm({ fileHash: this.fileHash, width, height, - x, - y, + x: width * (xPercent / 100), + y: height * (yPercent / 100), + xPercent, + yPercent, }); }, }, @@ -112,22 +124,19 @@ export default { type="button" @click="clickedToggle(discussion)" > - <gl-icon v-if="showCommentIcon" name="image-comment-dark" /> + <gl-icon v-if="showCommentIcon" name="image-comment-dark" :size="24" /> <template v-else> {{ toggleText(discussion, index) }} </template> </button> <button - v-if="currentCommentForm" - :style="{ - left: `${currentCommentForm.x}px`, - top: `${currentCommentForm.y}px`, - }" + v-if="canComment && currentCommentForm" + :style="{ left: `${currentCommentForm.xPercent}%`, top: `${currentCommentForm.yPercent}%` }" :aria-label="__('Comment form position')" - class="btn-transparent comment-indicator" + class="btn-transparent comment-indicator position-absolute" type="button" > - <gl-icon name="image-comment-dark" /> + <gl-icon name="image-comment-dark" :size="24" /> </button> </div> </template> diff --git a/app/assets/javascripts/diffs/components/merge_conflict_warning.vue b/app/assets/javascripts/diffs/components/merge_conflict_warning.vue index e47bea8e589..587efd6ed41 100644 --- a/app/assets/javascripts/diffs/components/merge_conflict_warning.vue +++ b/app/assets/javascripts/diffs/components/merge_conflict_warning.vue @@ -1,5 +1,5 @@ <script> -import { GlButton, GlAlert } from '@gitlab/ui'; +import { GlButton, GlAlert, GlModalDirective } from '@gitlab/ui'; import { CENTERED_LIMITED_CONTAINER_CLASSES } from '../constants'; export default { @@ -7,6 +7,9 @@ export default { GlAlert, GlButton, }, + directives: { + GlModalDirective, + }, props: { limited: { type: Boolean, @@ -60,9 +63,8 @@ export default { </gl-button> <gl-button v-if="mergeable" + v-gl-modal-directive="'modal-merge-info'" class="gl-alert-action" - data-toggle="modal" - data-target="#modal_merge_info" > {{ __('Merge locally') }} </gl-button> diff --git a/app/assets/javascripts/diffs/components/settings_dropdown.vue b/app/assets/javascripts/diffs/components/settings_dropdown.vue index 78647065c8e..2fe2fd6b3d8 100644 --- a/app/assets/javascripts/diffs/components/settings_dropdown.vue +++ b/app/assets/javascripts/diffs/components/settings_dropdown.vue @@ -1,23 +1,22 @@ <script> import { mapActions, mapGetters, mapState } from 'vuex'; -import { GlButtonGroup, GlButton, GlDropdown } from '@gitlab/ui'; -import { __ } from '~/locale'; +import { GlButtonGroup, GlButton, GlDropdown, GlFormCheckbox } from '@gitlab/ui'; + +import eventHub from '../event_hub'; +import { EVT_VIEW_FILE_BY_FILE } from '../constants'; +import { SETTINGS_DROPDOWN } from '../i18n'; export default { + i18n: SETTINGS_DROPDOWN, components: { GlButtonGroup, GlButton, GlDropdown, + GlFormCheckbox, }, computed: { ...mapGetters('diffs', ['isInlineView', 'isParallelView']), - ...mapState('diffs', ['renderTreeList', 'showWhitespace']), - }, - mounted() { - this.patchAriaLabel(); - }, - updated() { - this.patchAriaLabel(); + ...mapState('diffs', ['renderTreeList', 'showWhitespace', 'viewDiffsFileByFile']), }, methods: { ...mapActions('diffs', [ @@ -26,17 +25,21 @@ export default { 'setRenderTreeList', 'setShowWhitespace', ]), - patchAriaLabel() { - this.$el - .querySelector('.js-show-diff-settings') - .setAttribute('aria-label', __('Diff view settings')); + toggleFileByFile() { + eventHub.$emit(EVT_VIEW_FILE_BY_FILE, { setting: !this.viewDiffsFileByFile }); }, }, }; </script> <template> - <gl-dropdown icon="settings" toggle-class="js-show-diff-settings" right> + <gl-dropdown + icon="settings" + :text="__('Diff view settings')" + :text-sr-only="true" + toggle-class="js-show-diff-settings" + right + > <div class="gl-px-3"> <span class="gl-font-weight-bold gl-display-block gl-mb-2">{{ __('File browser') }}</span> <gl-button-group class="gl-display-flex"> @@ -90,5 +93,15 @@ export default { {{ __('Show whitespace changes') }} </label> </div> + <div class="gl-mt-3 gl-px-3"> + <gl-form-checkbox + data-testid="file-by-file" + class="gl-mb-0" + :checked="viewDiffsFileByFile" + @input="toggleFileByFile" + > + {{ $options.i18n.fileByFile }} + </gl-form-checkbox> + </div> </gl-dropdown> </template> diff --git a/app/assets/javascripts/diffs/constants.js b/app/assets/javascripts/diffs/constants.js index 79f8c08e389..07e27bd8e47 100644 --- a/app/assets/javascripts/diffs/constants.js +++ b/app/assets/javascripts/diffs/constants.js @@ -77,6 +77,11 @@ export const ALERT_COLLAPSED_FILES = 'collapsed'; export const DIFF_FILE_AUTOMATIC_COLLAPSE = 'automatic'; export const DIFF_FILE_MANUAL_COLLAPSE = 'manual'; +// Diff view single file mode +export const DIFF_FILE_BY_FILE_COOKIE_NAME = 'fileViewMode'; +export const DIFF_VIEW_FILE_BY_FILE = 'single'; +export const DIFF_VIEW_ALL_FILES = 'all'; + // State machine states export const STATE_IDLING = 'idle'; export const STATE_LOADING = 'loading'; @@ -98,6 +103,7 @@ export const RENAMED_DIFF_TRANSITIONS = { // MR Diffs known events export const EVT_EXPAND_ALL_FILES = 'mr:diffs:expandAllFiles'; +export const EVT_VIEW_FILE_BY_FILE = 'mr:diffs:preference:fileByFile'; export const EVT_PERF_MARK_FILE_TREE_START = 'mr:diffs:perf:fileTreeStart'; export const EVT_PERF_MARK_FILE_TREE_END = 'mr:diffs:perf:fileTreeEnd'; export const EVT_PERF_MARK_DIFF_FILES_START = 'mr:diffs:perf:filesStart'; diff --git a/app/assets/javascripts/diffs/i18n.js b/app/assets/javascripts/diffs/i18n.js index 4ec24d452bf..c4ac99ead91 100644 --- a/app/assets/javascripts/diffs/i18n.js +++ b/app/assets/javascripts/diffs/i18n.js @@ -16,3 +16,7 @@ export const DIFF_FILE = { autoCollapsed: __('Files with large changes are collapsed by default.'), expand: __('Expand file'), }; + +export const SETTINGS_DROPDOWN = { + fileByFile: __('Show one file at a time'), +}; diff --git a/app/assets/javascripts/diffs/index.js b/app/assets/javascripts/diffs/index.js index 06a138b1e13..587220488be 100644 --- a/app/assets/javascripts/diffs/index.js +++ b/app/assets/javascripts/diffs/index.js @@ -116,7 +116,7 @@ export default function initDiffsApp(store) { isFluidLayout: this.isFluidLayout, dismissEndpoint: this.dismissEndpoint, showSuggestPopover: this.showSuggestPopover, - viewDiffsFileByFile: this.viewDiffsFileByFile, + fileByFileUserPreference: this.viewDiffsFileByFile, }, }); }, diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index 91c4c51487f..5b410051705 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -30,13 +30,11 @@ import { OLD_LINE_KEY, NEW_LINE_KEY, TYPE_KEY, - LEFT_LINE_KEY, MAX_RENDERING_DIFF_LINES, MAX_RENDERING_BULK_ROWS, MIN_RENDERING_MS, START_RENDERING_INDEX, INLINE_DIFF_LINES_KEY, - PARALLEL_DIFF_LINES_KEY, DIFFS_PER_PAGE, DIFF_WHITESPACE_COOKIE_NAME, SHOW_WHITESPACE, @@ -46,9 +44,12 @@ import { EVT_PERF_MARK_FILE_TREE_START, EVT_PERF_MARK_FILE_TREE_END, EVT_PERF_MARK_DIFF_FILES_START, + DIFF_VIEW_FILE_BY_FILE, + DIFF_VIEW_ALL_FILES, + DIFF_FILE_BY_FILE_COOKIE_NAME, } from '../constants'; import { diffViewerModes } from '~/ide/constants'; -import { isCollapsed } from '../diff_file'; +import { isCollapsed } from '../utils/diff_file'; export const setBaseConfig = ({ commit }, options) => { const { @@ -59,6 +60,7 @@ export const setBaseConfig = ({ commit }, options) => { projectPath, dismissEndpoint, showSuggestPopover, + viewDiffsFileByFile, } = options; commit(types.SET_BASE_CONFIG, { endpoint, @@ -68,26 +70,38 @@ export const setBaseConfig = ({ commit }, options) => { projectPath, dismissEndpoint, showSuggestPopover, + viewDiffsFileByFile, }); }; export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => { + const diffsGradualLoad = window.gon?.features?.diffsGradualLoad; + let perPage = DIFFS_PER_PAGE; + let increaseAmount = 1.4; + + if (diffsGradualLoad) { + perPage = state.viewDiffsFileByFile ? 1 : 5; + } + + const startPage = diffsGradualLoad ? 0 : 1; const id = window?.location?.hash; const isNoteLink = id.indexOf('#note') === 0; const urlParams = { - per_page: DIFFS_PER_PAGE, w: state.showWhitespace ? '0' : '1', - view: window.gon?.features?.unifiedDiffLines ? 'inline' : state.diffViewType, + view: 'inline', }; + let totalLoaded = 0; commit(types.SET_BATCH_LOADING, true); commit(types.SET_RETRIEVING_BATCHES, true); eventHub.$emit(EVT_PERF_MARK_DIFF_FILES_START); - const getBatch = (page = 1) => + const getBatch = (page = startPage) => axios - .get(mergeUrlParams({ ...urlParams, page }, state.endpointBatch)) + .get(mergeUrlParams({ ...urlParams, page, per_page: perPage }, state.endpointBatch)) .then(({ data: { pagination, diff_files } }) => { + totalLoaded += diff_files.length; + commit(types.SET_DIFF_DATA_BATCH, { diff_files }); commit(types.SET_BATCH_LOADING, false); @@ -99,7 +113,11 @@ export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => { dispatch('setCurrentDiffFileIdFromNote', id.split('_').pop()); } - if (!pagination.next_page) { + if ( + (diffsGradualLoad && + (totalLoaded === pagination.total_pages || pagination.total_pages === null)) || + (!diffsGradualLoad && !pagination.next_page) + ) { commit(types.SET_RETRIEVING_BATCHES, false); // We need to check that the currentDiffFileId points to a file that exists @@ -125,6 +143,16 @@ export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => { }), ); } + + return null; + } + + if (diffsGradualLoad) { + const nextPage = page + perPage; + perPage = Math.min(Math.ceil(perPage * increaseAmount), 30); + increaseAmount = Math.min(increaseAmount + 0.2, 2); + + return nextPage; } return pagination.next_page; @@ -140,7 +168,7 @@ export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => { export const fetchDiffFilesMeta = ({ commit, state }) => { const worker = new TreeWorker(); const urlParams = { - view: window.gon?.features?.unifiedDiffLines ? 'inline' : state.diffViewType, + view: 'inline', }; commit(types.SET_LOADING, true); @@ -157,13 +185,19 @@ export const fetchDiffFilesMeta = ({ commit, state }) => { .get(mergeUrlParams(urlParams, state.endpointMetadata)) .then(({ data }) => { const strippedData = { ...data }; - delete strippedData.diff_files; + commit(types.SET_LOADING, false); commit(types.SET_MERGE_REQUEST_DIFFS, data.merge_request_diffs || []); - commit(types.SET_DIFF_DATA, strippedData); + commit(types.SET_DIFF_METADATA, strippedData); - worker.postMessage(prepareDiffData(data, state.diffFiles)); + worker.postMessage( + prepareDiffData({ + diff: data, + priorFiles: state.diffFiles, + meta: true, + }), + ); return data; }) @@ -401,15 +435,10 @@ export const toggleFileDiscussions = ({ getters, dispatch }, diff) => { export const toggleFileDiscussionWrappers = ({ commit }, diff) => { const discussionWrappersExpanded = allDiscussionWrappersExpanded(diff); const lineCodesWithDiscussions = new Set(); - const { parallel_diff_lines: parallelLines, highlighted_diff_lines: inlineLines } = diff; - const allLines = inlineLines.concat( - parallelLines.map(line => line.left), - parallelLines.map(line => line.right), - ); const lineHasDiscussion = line => Boolean(line?.discussions.length); const registerDiscussionLine = line => lineCodesWithDiscussions.add(line.line_code); - allLines.filter(lineHasDiscussion).forEach(registerDiscussionLine); + diff[INLINE_DIFF_LINES_KEY].filter(lineHasDiscussion).forEach(registerDiscussionLine); if (lineCodesWithDiscussions.size) { Array.from(lineCodesWithDiscussions).forEach(lineCode => { @@ -454,11 +483,11 @@ export const scrollToFile = ({ state, commit }, path) => { commit(types.VIEW_DIFF_FILE, fileHash); }; -export const toggleShowTreeList = ({ commit, state }, saving = true) => { - commit(types.TOGGLE_SHOW_TREE_LIST); +export const setShowTreeList = ({ commit }, { showTreeList, saving = true }) => { + commit(types.SET_SHOW_TREE_LIST, showTreeList); if (saving) { - localStorage.setItem(MR_TREE_SHOW_KEY, state.showTreeList); + localStorage.setItem(MR_TREE_SHOW_KEY, showTreeList); } }; @@ -508,61 +537,26 @@ export const receiveFullDiffError = ({ commit }, filePath) => { createFlash(s__('MergeRequest|Error loading full diff. Please try again.')); }; -export const setExpandedDiffLines = ({ commit, state }, { file, data }) => { - const expandedDiffLines = { - highlighted_diff_lines: convertExpandLines({ - diffLines: file.highlighted_diff_lines, - typeKey: TYPE_KEY, - oldLineKey: OLD_LINE_KEY, - newLineKey: NEW_LINE_KEY, - data, - mapLine: ({ line, oldLine, newLine }) => - Object.assign(line, { - old_line: oldLine, - new_line: newLine, - line_code: `${file.file_hash}_${oldLine}_${newLine}`, - }), - }), - parallel_diff_lines: convertExpandLines({ - diffLines: file.parallel_diff_lines, - typeKey: [LEFT_LINE_KEY, TYPE_KEY], - oldLineKey: [LEFT_LINE_KEY, OLD_LINE_KEY], - newLineKey: [LEFT_LINE_KEY, NEW_LINE_KEY], - data, - mapLine: ({ line, oldLine, newLine }) => ({ - left: { - ...line, - old_line: oldLine, - line_code: `${file.file_hash}_${oldLine}_${newLine}`, - }, - right: { - ...line, - new_line: newLine, - line_code: `${file.file_hash}_${newLine}_${oldLine}`, - }, +export const setExpandedDiffLines = ({ commit }, { file, data }) => { + const expandedDiffLines = convertExpandLines({ + diffLines: file[INLINE_DIFF_LINES_KEY], + typeKey: TYPE_KEY, + oldLineKey: OLD_LINE_KEY, + newLineKey: NEW_LINE_KEY, + data, + mapLine: ({ line, oldLine, newLine }) => + Object.assign(line, { + old_line: oldLine, + new_line: newLine, + line_code: `${file.file_hash}_${oldLine}_${newLine}`, }), - }), - }; - const unifiedDiffLinesEnabled = window.gon?.features?.unifiedDiffLines; - const currentDiffLinesKey = - state.diffViewType === INLINE_DIFF_VIEW_TYPE || unifiedDiffLinesEnabled - ? INLINE_DIFF_LINES_KEY - : PARALLEL_DIFF_LINES_KEY; - const hiddenDiffLinesKey = - state.diffViewType === INLINE_DIFF_VIEW_TYPE ? PARALLEL_DIFF_LINES_KEY : INLINE_DIFF_LINES_KEY; - - if (!unifiedDiffLinesEnabled) { - commit(types.SET_HIDDEN_VIEW_DIFF_FILE_LINES, { - filePath: file.file_path, - lines: expandedDiffLines[hiddenDiffLinesKey], - }); - } + }); - if (expandedDiffLines[currentDiffLinesKey].length > MAX_RENDERING_DIFF_LINES) { + if (expandedDiffLines.length > MAX_RENDERING_DIFF_LINES) { let index = START_RENDERING_INDEX; commit(types.SET_CURRENT_VIEW_DIFF_FILE_LINES, { filePath: file.file_path, - lines: expandedDiffLines[currentDiffLinesKey].slice(0, index), + lines: expandedDiffLines.slice(0, index), }); commit(types.TOGGLE_DIFF_FILE_RENDERING_MORE, file.file_path); @@ -571,10 +565,10 @@ export const setExpandedDiffLines = ({ commit, state }, { file, data }) => { while ( t.timeRemaining() >= MIN_RENDERING_MS && - index !== expandedDiffLines[currentDiffLinesKey].length && + index !== expandedDiffLines.length && index - startIndex !== MAX_RENDERING_BULK_ROWS ) { - const line = expandedDiffLines[currentDiffLinesKey][index]; + const line = expandedDiffLines[index]; if (line) { commit(types.ADD_CURRENT_VIEW_DIFF_FILE_LINES, { filePath: file.file_path, line }); @@ -582,7 +576,7 @@ export const setExpandedDiffLines = ({ commit, state }, { file, data }) => { } } - if (index !== expandedDiffLines[currentDiffLinesKey].length) { + if (index !== expandedDiffLines.length) { idleCallback(idleCb); } else { commit(types.TOGGLE_DIFF_FILE_RENDERING_MORE, file.file_path); @@ -593,7 +587,7 @@ export const setExpandedDiffLines = ({ commit, state }, { file, data }) => { } else { commit(types.SET_CURRENT_VIEW_DIFF_FILE_LINES, { filePath: file.file_path, - lines: expandedDiffLines[currentDiffLinesKey], + lines: expandedDiffLines, }); } }; @@ -627,7 +621,7 @@ export const toggleFullDiff = ({ dispatch, commit, getters, state }, filePath) = } }; -export function switchToFullDiffFromRenamedFile({ commit, dispatch, state }, { diffFile }) { +export function switchToFullDiffFromRenamedFile({ commit, dispatch }, { diffFile }) { return axios .get(diffFile.context_lines_path, { params: { @@ -638,7 +632,7 @@ export function switchToFullDiffFromRenamedFile({ commit, dispatch, state }, { d .then(({ data }) => { const lines = data.map((line, index) => prepareLineForRenamedFile({ - diffViewType: window.gon?.features?.unifiedDiffLines ? 'inline' : state.diffViewType, + diffViewType: 'inline', line, diffFile, index, @@ -736,3 +730,14 @@ export const navigateToDiffFileIndex = ({ commit, state }, index) => { commit(types.VIEW_DIFF_FILE, fileHash); }; + +export const setFileByFile = ({ commit }, { fileByFile }) => { + const fileViewMode = fileByFile ? DIFF_VIEW_FILE_BY_FILE : DIFF_VIEW_ALL_FILES; + commit(types.SET_FILE_BY_FILE, fileByFile); + + Cookies.set(DIFF_FILE_BY_FILE_COOKIE_NAME, fileViewMode); + + historyPushState( + mergeUrlParams({ [DIFF_FILE_BY_FILE_COOKIE_NAME]: fileViewMode }, window.location.href), + ); +}; diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js index 9ee73998177..baf54188932 100644 --- a/app/assets/javascripts/diffs/store/getters.js +++ b/app/assets/javascripts/diffs/store/getters.js @@ -1,6 +1,10 @@ import { __, n__ } from '~/locale'; import { parallelizeDiffLines } from './utils'; -import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '../constants'; +import { + PARALLEL_DIFF_VIEW_TYPE, + INLINE_DIFF_VIEW_TYPE, + INLINE_DIFF_LINES_KEY, +} from '../constants'; export * from './getters_versions_dropdowns'; @@ -54,24 +58,10 @@ export const diffHasAllCollapsedDiscussions = (state, getters) => diff => { * @param {Object} diff * @returns {Boolean} */ -export const diffHasExpandedDiscussions = state => diff => { - const lines = { - [INLINE_DIFF_VIEW_TYPE]: diff.highlighted_diff_lines || [], - [PARALLEL_DIFF_VIEW_TYPE]: (diff.parallel_diff_lines || []).reduce((acc, line) => { - if (line.left) { - acc.push(line.left); - } - - if (line.right) { - acc.push(line.right); - } - - return acc; - }, []), - }; - return lines[window.gon?.features?.unifiedDiffLines ? 'inline' : state.diffViewType] - .filter(l => l.discussions.length >= 1) - .some(l => l.discussionsExpanded); +export const diffHasExpandedDiscussions = () => diff => { + return diff[INLINE_DIFF_LINES_KEY].filter(l => l.discussions.length >= 1).some( + l => l.discussionsExpanded, + ); }; /** @@ -79,24 +69,8 @@ export const diffHasExpandedDiscussions = state => diff => { * @param {Boolean} diff * @returns {Boolean} */ -export const diffHasDiscussions = state => diff => { - const lines = { - [INLINE_DIFF_VIEW_TYPE]: diff.highlighted_diff_lines || [], - [PARALLEL_DIFF_VIEW_TYPE]: (diff.parallel_diff_lines || []).reduce((acc, line) => { - if (line.left) { - acc.push(line.left); - } - - if (line.right) { - acc.push(line.right); - } - - return acc; - }, []), - }; - return lines[window.gon?.features?.unifiedDiffLines ? 'inline' : state.diffViewType].some( - l => l.discussions.length >= 1, - ); +export const diffHasDiscussions = () => diff => { + return diff[INLINE_DIFF_LINES_KEY].some(l => l.discussions.length >= 1); }; /** diff --git a/app/assets/javascripts/diffs/store/modules/diff_state.js b/app/assets/javascripts/diffs/store/modules/diff_state.js index 001d9d9f594..c331e52c887 100644 --- a/app/assets/javascripts/diffs/store/modules/diff_state.js +++ b/app/assets/javascripts/diffs/store/modules/diff_state.js @@ -5,6 +5,8 @@ import { DIFF_VIEW_COOKIE_NAME, DIFF_WHITESPACE_COOKIE_NAME, } from '../../constants'; + +import { fileByFile } from '../../utils/preferences'; import { getDefaultWhitespace } from '../utils'; const viewTypeFromQueryString = getParameterValues('view')[0]; @@ -39,6 +41,7 @@ export default () => ({ highlightedRow: null, renderTreeList: true, showWhitespace: getDefaultWhitespace(whiteSpaceFromQueryString, whiteSpaceFromCookie), + viewDiffsFileByFile: fileByFile(), fileFinderVisible: false, dismissEndpoint: '', showSuggestPopover: true, diff --git a/app/assets/javascripts/diffs/store/mutation_types.js b/app/assets/javascripts/diffs/store/mutation_types.js index 19a9e65edc9..30097239aaa 100644 --- a/app/assets/javascripts/diffs/store/mutation_types.js +++ b/app/assets/javascripts/diffs/store/mutation_types.js @@ -3,7 +3,7 @@ export const SET_LOADING = 'SET_LOADING'; export const SET_BATCH_LOADING = 'SET_BATCH_LOADING'; export const SET_RETRIEVING_BATCHES = 'SET_RETRIEVING_BATCHES'; -export const SET_DIFF_DATA = 'SET_DIFF_DATA'; +export const SET_DIFF_METADATA = 'SET_DIFF_METADATA'; export const SET_DIFF_DATA_BATCH = 'SET_DIFF_DATA_BATCH'; export const SET_DIFF_FILES = 'SET_DIFF_FILES'; @@ -17,7 +17,7 @@ export const RENDER_FILE = 'RENDER_FILE'; export const SET_LINE_DISCUSSIONS_FOR_FILE = 'SET_LINE_DISCUSSIONS_FOR_FILE'; export const REMOVE_LINE_DISCUSSIONS_FOR_FILE = 'REMOVE_LINE_DISCUSSIONS_FOR_FILE'; export const TOGGLE_FOLDER_OPEN = 'TOGGLE_FOLDER_OPEN'; -export const TOGGLE_SHOW_TREE_LIST = 'TOGGLE_SHOW_TREE_LIST'; +export const SET_SHOW_TREE_LIST = 'SET_SHOW_TREE_LIST'; export const VIEW_DIFF_FILE = 'VIEW_DIFF_FILE'; export const OPEN_DIFF_FILE_COMMENT_FORM = 'OPEN_DIFF_FILE_COMMENT_FORM'; @@ -28,6 +28,7 @@ export const SET_HIGHLIGHTED_ROW = 'SET_HIGHLIGHTED_ROW'; export const SET_TREE_DATA = 'SET_TREE_DATA'; export const SET_RENDER_TREE_LIST = 'SET_RENDER_TREE_LIST'; export const SET_SHOW_WHITESPACE = 'SET_SHOW_WHITESPACE'; +export const SET_FILE_BY_FILE = 'SET_FILE_BY_FILE'; export const TOGGLE_FILE_FINDER_VISIBLE = 'TOGGLE_FILE_FINDER_VISIBLE'; export const REQUEST_FULL_DIFF = 'REQUEST_FULL_DIFF'; @@ -35,7 +36,6 @@ export const RECEIVE_FULL_DIFF_SUCCESS = 'RECEIVE_FULL_DIFF_SUCCESS'; export const RECEIVE_FULL_DIFF_ERROR = 'RECEIVE_FULL_DIFF_ERROR'; export const SET_FILE_COLLAPSED = 'SET_FILE_COLLAPSED'; -export const SET_HIDDEN_VIEW_DIFF_FILE_LINES = 'SET_HIDDEN_VIEW_DIFF_FILE_LINES'; export const SET_CURRENT_VIEW_DIFF_FILE_LINES = 'SET_CURRENT_VIEW_DIFF_FILE_LINES'; export const ADD_CURRENT_VIEW_DIFF_FILE_LINES = 'ADD_CURRENT_VIEW_DIFF_FILE_LINES'; export const TOGGLE_DIFF_FILE_RENDERING_MORE = 'TOGGLE_DIFF_FILE_RENDERING_MORE'; diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index 096c4f69439..19122c3096f 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -1,11 +1,6 @@ import Vue from 'vue'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { - DIFF_FILE_MANUAL_COLLAPSE, - DIFF_FILE_AUTOMATIC_COLLAPSE, - INLINE_DIFF_VIEW_TYPE, -} from '../constants'; -import { findDiffFile, addLineReferences, removeMatchLine, @@ -14,6 +9,11 @@ import { isDiscussionApplicableToLine, updateLineInFile, } from './utils'; +import { + DIFF_FILE_MANUAL_COLLAPSE, + DIFF_FILE_AUTOMATIC_COLLAPSE, + INLINE_DIFF_LINES_KEY, +} from '../constants'; import * as types from './mutation_types'; function updateDiffFilesInState(state, files) { @@ -36,6 +36,7 @@ export default { projectPath, dismissEndpoint, showSuggestPopover, + viewDiffsFileByFile, } = options; Object.assign(state, { endpoint, @@ -45,6 +46,7 @@ export default { projectPath, dismissEndpoint, showSuggestPopover, + viewDiffsFileByFile, }); }, @@ -64,21 +66,17 @@ export default { updateDiffFilesInState(state, files); }, - [types.SET_DIFF_DATA](state, data) { - let files = state.diffFiles; - - if (window.location.search.indexOf('diff_id') !== -1 && data.diff_files) { - files = prepareDiffData(data, files); - } - + [types.SET_DIFF_METADATA](state, data) { Object.assign(state, { ...convertObjectPropsToCamelCase(data), }); - updateDiffFilesInState(state, files); }, [types.SET_DIFF_DATA_BATCH](state, data) { - const files = prepareDiffData(data, state.diffFiles); + const files = prepareDiffData({ + diff: data, + priorFiles: state.diffFiles, + }); Object.assign(state, { ...convertObjectPropsToCamelCase(data), @@ -109,25 +107,7 @@ export default { if (!diffFile) return; - if (diffFile.highlighted_diff_lines.length) { - diffFile.highlighted_diff_lines.find(l => l.line_code === lineCode).hasForm = hasForm; - } - - if (diffFile.parallel_diff_lines.length) { - const line = diffFile.parallel_diff_lines.find(l => { - const { left, right } = l; - - return (left && left.line_code === lineCode) || (right && right.line_code === lineCode); - }); - - if (line.left && line.left.line_code === lineCode) { - line.left.hasForm = hasForm; - } - - if (line.right && line.right.line_code === lineCode) { - line.right.hasForm = hasForm; - } - } + diffFile[INLINE_DIFF_LINES_KEY].find(l => l.line_code === lineCode).hasForm = hasForm; }, [types.ADD_CONTEXT_LINES](state, options) { @@ -157,11 +137,7 @@ export default { }); addContextLines({ - inlineLines: diffFile.highlighted_diff_lines, - parallelLines: diffFile.parallel_diff_lines, - diffViewType: window.gon?.features?.unifiedDiffLines - ? INLINE_DIFF_VIEW_TYPE - : state.diffViewType, + inlineLines: diffFile[INLINE_DIFF_LINES_KEY], contextLines: lines, bottom, lineNumbers, @@ -170,7 +146,7 @@ export default { }, [types.ADD_COLLAPSED_DIFFS](state, { file, data }) { - const files = prepareDiffData(data); + const files = prepareDiffData({ diff: data }); const [newFileData] = files.filter(f => f.file_hash === file.file_hash); const selectedFile = state.diffFiles.find(f => f.file_hash === file.file_hash); Object.assign(selectedFile, { ...newFileData }); @@ -219,8 +195,8 @@ export default { state.diffFiles.forEach(file => { if (file.file_hash === fileHash) { - if (file.highlighted_diff_lines.length) { - file.highlighted_diff_lines.forEach(line => { + if (file[INLINE_DIFF_LINES_KEY].length) { + file[INLINE_DIFF_LINES_KEY].forEach(line => { Object.assign( line, setDiscussionsExpanded(lineCheck(line) ? mapDiscussions(line) : line), @@ -228,25 +204,7 @@ export default { }); } - if (file.parallel_diff_lines.length) { - file.parallel_diff_lines.forEach(line => { - const left = line.left && lineCheck(line.left); - const right = line.right && lineCheck(line.right); - - if (left || right) { - Object.assign(line, { - left: line.left ? setDiscussionsExpanded(mapDiscussions(line.left)) : null, - right: line.right - ? setDiscussionsExpanded(mapDiscussions(line.right, () => !left)) - : null, - }); - } - - return line; - }); - } - - if (!file.parallel_diff_lines.length || !file.highlighted_diff_lines.length) { + if (!file[INLINE_DIFF_LINES_KEY].length) { const newDiscussions = (file.discussions || []) .filter(d => d.id !== discussion.id) .concat(discussion); @@ -287,8 +245,8 @@ export default { [types.TOGGLE_FOLDER_OPEN](state, path) { state.treeEntries[path].opened = !state.treeEntries[path].opened; }, - [types.TOGGLE_SHOW_TREE_LIST](state) { - state.showTreeList = !state.showTreeList; + [types.SET_SHOW_TREE_LIST](state, showTreeList) { + state.showTreeList = showTreeList; }, [types.VIEW_DIFF_FILE](state, fileId) { state.currentDiffFileId = fileId; @@ -369,31 +327,15 @@ export default { renderFile(file); } }, - [types.SET_HIDDEN_VIEW_DIFF_FILE_LINES](state, { filePath, lines }) { - const file = state.diffFiles.find(f => f.file_path === filePath); - const hiddenDiffLinesKey = - state.diffViewType === 'inline' ? 'parallel_diff_lines' : 'highlighted_diff_lines'; - - file[hiddenDiffLinesKey] = lines; - }, [types.SET_CURRENT_VIEW_DIFF_FILE_LINES](state, { filePath, lines }) { const file = state.diffFiles.find(f => f.file_path === filePath); - let currentDiffLinesKey; - if (window.gon?.features?.unifiedDiffLines || state.diffViewType === 'inline') { - currentDiffLinesKey = 'highlighted_diff_lines'; - } else { - currentDiffLinesKey = 'parallel_diff_lines'; - } - - file[currentDiffLinesKey] = lines; + file[INLINE_DIFF_LINES_KEY] = lines; }, [types.ADD_CURRENT_VIEW_DIFF_FILE_LINES](state, { filePath, line }) { const file = state.diffFiles.find(f => f.file_path === filePath); - const currentDiffLinesKey = - state.diffViewType === 'inline' ? 'highlighted_diff_lines' : 'parallel_diff_lines'; - file[currentDiffLinesKey].push(line); + file[INLINE_DIFF_LINES_KEY].push(line); }, [types.TOGGLE_DIFF_FILE_RENDERING_MORE](state, filePath) { const file = state.diffFiles.find(f => f.file_path === filePath); @@ -408,4 +350,7 @@ export default { [types.SET_SHOW_SUGGEST_POPOVER](state) { state.showSuggestPopover = false; }, + [types.SET_FILE_BY_FILE](state, fileByFile) { + state.viewDiffsFileByFile = fileByFile; + }, }; diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js index f87f57c32c3..1839df12c96 100644 --- a/app/assets/javascripts/diffs/store/utils.js +++ b/app/assets/javascripts/diffs/store/utils.js @@ -12,12 +12,11 @@ import { MATCH_LINE_TYPE, LINES_TO_BE_RENDERED_DIRECTLY, TREE_TYPE, - INLINE_DIFF_VIEW_TYPE, - PARALLEL_DIFF_VIEW_TYPE, + INLINE_DIFF_LINES_KEY, SHOW_WHITESPACE, NO_SHOW_WHITESPACE, } from '../constants'; -import { prepareRawDiffFile } from '../diff_file'; +import { prepareRawDiffFile } from '../utils/diff_file'; export const isAdded = line => ['new', 'new-nonewline'].includes(line.type); export const isRemoved = line => ['old', 'old-nonewline'].includes(line.type); @@ -48,7 +47,7 @@ export const parallelizeDiffLines = (diffLines, inline) => { for (let i = 0, diffLinesLength = diffLines.length, index = 0; i < diffLinesLength; i += 1) { const line = diffLines[i]; - if (isRemoved(line)) { + if (isRemoved(line) || inline) { lines.push({ [LINE_POSITION_LEFT]: line, [LINE_POSITION_RIGHT]: null, @@ -60,7 +59,7 @@ export const parallelizeDiffLines = (diffLines, inline) => { } index += 1; } else if (isAdded(line)) { - if (freeRightIndex !== null && !inline) { + if (freeRightIndex !== null) { // If an old line came before this without a line on the right, this // line can be put to the right of it. lines[freeRightIndex].right = line; @@ -178,43 +177,16 @@ export const findIndexInInlineLines = (lines, lineNumbers) => { ); }; -export const findIndexInParallelLines = (lines, lineNumbers) => { - const { oldLineNumber, newLineNumber } = lineNumbers; - - return lines.findIndex( - line => - line.left && - line.right && - line.left.old_line === oldLineNumber && - line.right.new_line === newLineNumber, - ); -}; - -const indexGettersByViewType = { - [INLINE_DIFF_VIEW_TYPE]: findIndexInInlineLines, - [PARALLEL_DIFF_VIEW_TYPE]: findIndexInParallelLines, -}; - export const getPreviousLineIndex = (diffViewType, file, lineNumbers) => { - const findIndex = indexGettersByViewType[diffViewType]; - const lines = { - [INLINE_DIFF_VIEW_TYPE]: file.highlighted_diff_lines, - [PARALLEL_DIFF_VIEW_TYPE]: file.parallel_diff_lines, - }; - - return findIndex && findIndex(lines[diffViewType], lineNumbers); + return findIndexInInlineLines(file[INLINE_DIFF_LINES_KEY], lineNumbers); }; export function removeMatchLine(diffFile, lineNumbers, bottom) { - const indexForInline = findIndexInInlineLines(diffFile.highlighted_diff_lines, lineNumbers); - const indexForParallel = findIndexInParallelLines(diffFile.parallel_diff_lines, lineNumbers); + const indexForInline = findIndexInInlineLines(diffFile[INLINE_DIFF_LINES_KEY], lineNumbers); const factor = bottom ? 1 : -1; if (indexForInline > -1) { - diffFile.highlighted_diff_lines.splice(indexForInline + factor, 1); - } - if (indexForParallel > -1) { - diffFile.parallel_diff_lines.splice(indexForParallel + factor, 1); + diffFile[INLINE_DIFF_LINES_KEY].splice(indexForInline + factor, 1); } } @@ -257,24 +229,6 @@ export function addLineReferences(lines, lineNumbers, bottom, isExpandDown, next return linesWithNumbers; } -function addParallelContextLines(options) { - const { parallelLines, contextLines, lineNumbers, isExpandDown } = options; - const normalizedParallelLines = contextLines.map(line => ({ - left: line, - right: line, - line_code: line.line_code, - })); - const factor = isExpandDown ? 1 : 0; - - if (!isExpandDown && options.bottom) { - parallelLines.push(...normalizedParallelLines); - } else { - const parallelIndex = findIndexInParallelLines(parallelLines, lineNumbers); - - parallelLines.splice(parallelIndex + factor, 0, ...normalizedParallelLines); - } -} - function addInlineContextLines(options) { const { inlineLines, contextLines, lineNumbers, isExpandDown } = options; const factor = isExpandDown ? 1 : 0; @@ -289,16 +243,7 @@ function addInlineContextLines(options) { } export function addContextLines(options) { - const { diffViewType } = options; - const contextLineHandlers = { - [INLINE_DIFF_VIEW_TYPE]: addInlineContextLines, - [PARALLEL_DIFF_VIEW_TYPE]: addParallelContextLines, - }; - const contextLineHandler = contextLineHandlers[diffViewType]; - - if (contextLineHandler) { - contextLineHandler(options); - } + addInlineContextLines(options); } /** @@ -324,41 +269,29 @@ export function trimFirstCharOfLineContent(line = {}) { return parsedLine; } -function getLineCode({ left, right }, index) { - if (left && left.line_code) { - return left.line_code; - } else if (right && right.line_code) { - return right.line_code; - } - return index; -} - function diffFileUniqueId(file) { return `${file.content_sha}-${file.file_hash}`; } function mergeTwoFiles(target, source) { - const originalInline = target.highlighted_diff_lines; - const originalParallel = target.parallel_diff_lines; + const originalInline = target[INLINE_DIFF_LINES_KEY]; const missingInline = !originalInline.length; - const missingParallel = !originalParallel.length; return { ...target, - highlighted_diff_lines: missingInline ? source.highlighted_diff_lines : originalInline, - parallel_diff_lines: missingParallel ? source.parallel_diff_lines : originalParallel, + [INLINE_DIFF_LINES_KEY]: missingInline ? source[INLINE_DIFF_LINES_KEY] : originalInline, + parallel_diff_lines: null, renderIt: source.renderIt, collapsed: source.collapsed, }; } function ensureBasicDiffFileLines(file) { - const missingInline = !file.highlighted_diff_lines; - const missingParallel = !file.parallel_diff_lines || window.gon?.features?.unifiedDiffLines; + const missingInline = !file[INLINE_DIFF_LINES_KEY]; Object.assign(file, { - highlighted_diff_lines: missingInline ? [] : file.highlighted_diff_lines, - parallel_diff_lines: missingParallel ? [] : file.parallel_diff_lines, + [INLINE_DIFF_LINES_KEY]: missingInline ? [] : file[INLINE_DIFF_LINES_KEY], + parallel_diff_lines: null, }); return file; @@ -382,7 +315,7 @@ function prepareLine(line, file) { } } -export function prepareLineForRenamedFile({ line, diffViewType, diffFile, index = 0 }) { +export function prepareLineForRenamedFile({ line, diffFile, index = 0 }) { /* Renamed files are a little different than other diffs, which is why this is distinct from `prepareDiffFileLines` below. @@ -407,48 +340,23 @@ export function prepareLineForRenamedFile({ line, diffViewType, diffFile, index prepareLine(cleanLine, diffFile); // WARNING: In-Place Mutations! - if (diffViewType === PARALLEL_DIFF_VIEW_TYPE) { - return { - left: { ...cleanLine }, - right: { ...cleanLine }, - line_code: cleanLine.line_code, - }; - } - return cleanLine; } function prepareDiffFileLines(file) { - const inlineLines = file.highlighted_diff_lines; - const parallelLines = file.parallel_diff_lines; - let parallelLinesCount = 0; + const inlineLines = file[INLINE_DIFF_LINES_KEY]; inlineLines.forEach(line => prepareLine(line, file)); // WARNING: In-Place Mutations! - parallelLines.forEach((line, index) => { - Object.assign(line, { line_code: getLineCode(line, index) }); - - if (line.left) { - parallelLinesCount += 1; - prepareLine(line.left, file); // WARNING: In-Place Mutations! - } - - if (line.right) { - parallelLinesCount += 1; - prepareLine(line.right, file); // WARNING: In-Place Mutations! - } - }); - Object.assign(file, { inlineLinesCount: inlineLines.length, - parallelLinesCount, }); return file; } function getVisibleDiffLines(file) { - return Math.max(file.inlineLinesCount, file.parallelLinesCount); + return file.inlineLinesCount; } function finalizeDiffFile(file) { @@ -478,9 +386,9 @@ function deduplicateFilesList(files) { return Object.values(dedupedFiles); } -export function prepareDiffData(diff, priorFiles = []) { +export function prepareDiffData({ diff, priorFiles = [], meta = false }) { const cleanedFiles = (diff.diff_files || []) - .map((file, index, allFiles) => prepareRawDiffFile({ file, allFiles })) + .map((file, index, allFiles) => prepareRawDiffFile({ file, allFiles, meta })) .map(ensureBasicDiffFileLines) .map(prepareDiffFileLines) .map(finalizeDiffFile); @@ -490,43 +398,14 @@ export function prepareDiffData(diff, priorFiles = []) { export function getDiffPositionByLineCode(diffFiles) { let lines = []; - const hasInlineDiffs = diffFiles.some(file => file.highlighted_diff_lines.length > 0); - - if (hasInlineDiffs) { - // In either of these cases, we can use `highlighted_diff_lines` because - // that will include all of the parallel diff lines, too - - lines = diffFiles.reduce((acc, diffFile) => { - diffFile.highlighted_diff_lines.forEach(line => { - acc.push({ file: diffFile, line }); - }); - - return acc; - }, []); - } else { - // If we're in single diff view mode and the inline lines haven't been - // loaded yet, we need to parse the parallel lines - - lines = diffFiles.reduce((acc, diffFile) => { - diffFile.parallel_diff_lines.forEach(pair => { - // It's possible for a parallel line to have an opposite line that doesn't exist - // For example: *deleted* lines will have `null` right lines, while - // *added* lines will have `null` left lines. - // So we have to check each line before we push it onto the array so we're not - // pushing null line diffs - - if (pair.left) { - acc.push({ file: diffFile, line: pair.left }); - } - if (pair.right) { - acc.push({ file: diffFile, line: pair.right }); - } - }); + lines = diffFiles.reduce((acc, diffFile) => { + diffFile[INLINE_DIFF_LINES_KEY].forEach(line => { + acc.push({ file: diffFile, line }); + }); - return acc; - }, []); - } + return acc; + }, []); return lines.reduce((acc, { file, line }) => { if (line.line_code) { @@ -739,24 +618,10 @@ export const convertExpandLines = ({ export const idleCallback = cb => requestIdleCallback(cb); function getLinesFromFileByLineCode(file, lineCode) { - const parallelLines = file.parallel_diff_lines; - const inlineLines = file.highlighted_diff_lines; + const inlineLines = file[INLINE_DIFF_LINES_KEY]; const matchesCode = line => line.line_code === lineCode; - return [ - ...parallelLines.reduce((acc, line) => { - if (line.left) { - acc.push(line.left); - } - - if (line.right) { - acc.push(line.right); - } - - return acc; - }, []), - ...inlineLines, - ].filter(matchesCode); + return inlineLines.filter(matchesCode); } export const updateLineInFile = (selectedFile, lineCode, updateFn) => { @@ -771,12 +636,7 @@ export const allDiscussionWrappersExpanded = diff => { } }; - diff.parallel_diff_lines.forEach(line => { - changeExpandedResult(line.left); - changeExpandedResult(line.right); - }); - - diff.highlighted_diff_lines.forEach(line => { + diff[INLINE_DIFF_LINES_KEY].forEach(line => { changeExpandedResult(line); }); diff --git a/app/assets/javascripts/diffs/diff_file.js b/app/assets/javascripts/diffs/utils/diff_file.js index a14a30b41a9..69d0e49e501 100644 --- a/app/assets/javascripts/diffs/diff_file.js +++ b/app/assets/javascripts/diffs/utils/diff_file.js @@ -3,7 +3,8 @@ import { DIFF_FILE_DELETED_MODE, DIFF_FILE_MANUAL_COLLAPSE, DIFF_FILE_AUTOMATIC_COLLAPSE, -} from './constants'; +} from '../constants'; +import { uuids } from './uuids'; function fileSymlinkInformation(file, fileList) { const duplicates = fileList.filter(iteratedFile => iteratedFile.file_hash === file.file_hash); @@ -32,16 +33,29 @@ function collapsed(file) { }; } -export function prepareRawDiffFile({ file, allFiles }) { - Object.assign(file, { +function identifier(file) { + return uuids({ + seeds: [file.file_identifier_hash, file.blob?.id], + })[0]; +} + +export function prepareRawDiffFile({ file, allFiles, meta = false }) { + const additionalProperties = { brokenSymlink: fileSymlinkInformation(file, allFiles), viewer: { ...file.viewer, ...collapsed(file), }, - }); + }; + + // It's possible, but not confirmed, that `content_sha` isn't available sometimes + // See: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49506#note_464692057 + // We don't want duplicate IDs if that's the case, so we just don't assign an ID + if (!meta && file.blob?.id) { + additionalProperties.id = identifier(file); + } - return file; + return Object.assign(file, additionalProperties); } export function collapsedType(file) { diff --git a/app/assets/javascripts/diffs/utils/preferences.js b/app/assets/javascripts/diffs/utils/preferences.js new file mode 100644 index 00000000000..e440de3350a --- /dev/null +++ b/app/assets/javascripts/diffs/utils/preferences.js @@ -0,0 +1,22 @@ +import Cookies from 'js-cookie'; +import { getParameterValues } from '~/lib/utils/url_utility'; + +import { DIFF_FILE_BY_FILE_COOKIE_NAME, DIFF_VIEW_FILE_BY_FILE } from '../constants'; + +export function fileByFile(pref = false) { + const search = getParameterValues(DIFF_FILE_BY_FILE_COOKIE_NAME)?.[0]; + const cookie = Cookies.get(DIFF_FILE_BY_FILE_COOKIE_NAME); + let viewFileByFile = pref; + + // use the cookie first, if it exists + if (cookie) { + viewFileByFile = cookie === DIFF_VIEW_FILE_BY_FILE; + } + + // the search parameter of the URL should override, if it exists + if (search) { + viewFileByFile = search === DIFF_VIEW_FILE_BY_FILE; + } + + return viewFileByFile; +} |