diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-10-21 07:08:36 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-10-21 07:08:36 +0000 |
commit | 48aff82709769b098321c738f3444b9bdaa694c6 (patch) | |
tree | e00c7c43e2d9b603a5a6af576b1685e400410dee /app/assets/javascripts/diffs | |
parent | 879f5329ee916a948223f8f43d77fba4da6cd028 (diff) | |
download | gitlab-ce-48aff82709769b098321c738f3444b9bdaa694c6.tar.gz |
Add latest changes from gitlab-org/gitlab@13-5-stable-eev13.5.0-rc42
Diffstat (limited to 'app/assets/javascripts/diffs')
21 files changed, 420 insertions, 683 deletions
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index dd5addbf1e3..085f951147f 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -474,7 +474,7 @@ export default { <div v-if="showTreeList" :style="{ width: `${treeWidth}px` }" - class="diff-tree-list js-diff-tree-list mr-3" + class="diff-tree-list js-diff-tree-list px-3 pr-md-0" > <panel-resizer :size.sync="treeWidth" @@ -487,7 +487,7 @@ export default { <tree-list :hide-file-stats="hideFileStats" /> </div> <div - class="diff-files-holder" + class="col-12 col-md-auto diff-files-holder" :class="{ [CENTERED_LIMITED_CONTAINER_CLASSES]: isLimitedContainer, }" diff --git a/app/assets/javascripts/diffs/components/collapsed_files_warning.vue b/app/assets/javascripts/diffs/components/collapsed_files_warning.vue index dded3643115..270bbfb99b7 100644 --- a/app/assets/javascripts/diffs/components/collapsed_files_warning.vue +++ b/app/assets/javascripts/diffs/components/collapsed_files_warning.vue @@ -50,7 +50,7 @@ export default { </script> <template> - <div v-if="!isDismissed" data-testid="root" :class="containerClasses"> + <div v-if="!isDismissed" data-testid="root" :class="containerClasses" class="col-12"> <gl-alert :dismissible="true" :title="__('Some changes are not shown')" diff --git a/app/assets/javascripts/diffs/components/commit_item.vue b/app/assets/javascripts/diffs/components/commit_item.vue index 23669eecce2..1b747fb7f20 100644 --- a/app/assets/javascripts/diffs/components/commit_item.vue +++ b/app/assets/javascripts/diffs/components/commit_item.vue @@ -1,7 +1,7 @@ <script> /* eslint-disable vue/no-v-html */ import { mapActions } from 'vuex'; -import { GlButtonGroup, GlButton, GlIcon, GlTooltipDirective } from '@gitlab/ui'; +import { GlButtonGroup, GlButton, GlTooltipDirective, GlIcon } from '@gitlab/ui'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; @@ -122,74 +122,27 @@ export default { </script> <template> - <li :class="{ 'js-toggle-container': collapsible }" class="commit flex-row"> - <div class="d-flex align-items-center align-self-start"> - <input - v-if="isSelectable" - class="mr-2" - type="checkbox" - :checked="checked" - @change="$emit('handleCheckboxChange', $event.target.checked)" - /> - <user-avatar-link - :link-href="authorUrl" - :img-src="authorAvatar" - :img-alt="authorName" - :img-size="40" - class="avatar-cell d-none d-sm-block" - /> - </div> - <div class="commit-detail flex-list"> - <div class="commit-content qa-commit-content"> - <a - :href="commit.commit_url" - class="commit-row-message item-title" - v-html="commit.title_html" - ></a> - - <span class="commit-row-message d-block d-sm-none">· {{ commit.short_id }}</span> - - <gl-button - v-if="commit.description_html && collapsible" - class="js-toggle-button" - size="small" - icon="ellipsis_h" - :aria-label="__('Toggle commit description')" - /> - - <div class="committer"> - <a - :href="authorUrl" - :class="authorClass" - :data-user-id="authorId" - v-text="authorName" - ></a> - {{ s__('CommitWidget|authored') }} - <time-ago-tooltip :time="commit.authored_date" /> - </div> - - <pre - v-if="commit.description_html" - :class="{ 'js-toggle-content': collapsible, 'd-block': !collapsible }" - class="commit-row-description gl-mb-3 text-dark" - v-html="commitDescription" - ></pre> - </div> - <div class="commit-actions flex-row d-none d-sm-flex"> + <li :class="{ 'js-toggle-container': collapsible }" class="commit"> + <div + class="d-block d-sm-flex flex-row-reverse justify-content-between align-items-start flex-lg-row-reverse" + > + <div + class="commit-actions flex-row d-none d-sm-flex align-items-start flex-wrap justify-content-end" + > <div v-if="commit.signature_html" v-html="commit.signature_html"></div> <commit-pipeline-status v-if="commit.pipeline_status_path" :endpoint="commit.pipeline_status_path" - class="d-inline-flex" + class="d-inline-flex mb-2" /> - <div class="commit-sha-group"> - <div class="label label-monospace monospace" v-text="commit.short_id"></div> + <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" /> <clipboard-button :text="commit.id" :title="__('Copy commit SHA')" - class="btn btn-default" + class="input-group-text" /> - </div> + </gl-button-group> <div v-if="hasNeighborCommits && glFeatures.mrCommitNeighborNav" class="commit-nav-buttons ml-3" @@ -226,6 +179,62 @@ export default { </gl-button-group> </div> </div> + <div> + <div class="d-flex float-left align-items-center align-self-start"> + <input + v-if="isSelectable" + class="mr-2" + type="checkbox" + :checked="checked" + @change="$emit('handleCheckboxChange', $event.target.checked)" + /> + <user-avatar-link + :link-href="authorUrl" + :img-src="authorAvatar" + :img-alt="authorName" + :img-size="40" + class="avatar-cell d-none d-sm-block" + /> + </div> + <div class="commit-detail flex-list"> + <div class="commit-content qa-commit-content"> + <a + :href="commit.commit_url" + class="commit-row-message item-title" + v-html="commit.title_html" + ></a> + + <span class="commit-row-message d-block d-sm-none">· {{ commit.short_id }}</span> + + <gl-button + v-if="commit.description_html && collapsible" + class="js-toggle-button" + size="small" + icon="ellipsis_h" + :aria-label="__('Toggle commit description')" + /> + + <div class="committer"> + <a + :href="authorUrl" + :class="authorClass" + :data-user-id="authorId" + v-text="authorName" + ></a> + {{ s__('CommitWidget|authored') }} + <time-ago-tooltip :time="commit.authored_date" /> + </div> + </div> + </div> + </div> + </div> + <div> + <pre + v-if="commit.description_html" + :class="{ 'js-toggle-content': collapsible, 'd-block': !collapsible }" + class="commit-row-description gl-mb-3 text-dark" + v-html="commitDescription" + ></pre> </div> </li> </template> diff --git a/app/assets/javascripts/diffs/components/commit_widget.vue b/app/assets/javascripts/diffs/components/commit_widget.vue index 5c7e84bd87c..b1a2b2a72ea 100644 --- a/app/assets/javascripts/diffs/components/commit_widget.vue +++ b/app/assets/javascripts/diffs/components/commit_widget.vue @@ -1,19 +1,6 @@ <script> import CommitItem from './commit_item.vue'; -/** - * CommitWidget - * - * ----------------------------------------------------------------- - * WARNING: Please keep changes up-to-date with the following files: - * - `views/projects/merge_requests/diffs/_commit_widget.html.haml` - * ----------------------------------------------------------------- - * - * This Component was cloned from a HAML view. For the time being, - * they coexist, but there is an issue to remove the duplication. - * https://gitlab.com/gitlab-org/gitlab-foss/issues/51613 - * - */ export default { components: { CommitItem, diff --git a/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue b/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue index 8263e938e69..adef5d94624 100644 --- a/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue +++ b/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue @@ -32,7 +32,7 @@ export default { <gl-icon :size="12" name="angle-down" class="position-absolute" /> </a> <div class="dropdown-menu dropdown-select dropdown-menu-selectable"> - <div class="dropdown-content"> + <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"> diff --git a/app/assets/javascripts/diffs/components/compare_versions.vue b/app/assets/javascripts/diffs/components/compare_versions.vue index b94874c5644..b1ebd8e6ebc 100644 --- a/app/assets/javascripts/diffs/components/compare_versions.vue +++ b/app/assets/javascripts/diffs/components/compare_versions.vue @@ -100,6 +100,7 @@ export default { <compare-dropdown-layout :versions="diffCompareDropdownTargetVersions" class="mr-version-compare-dropdown" + data-qa-selector="target_version_dropdown" /> </template> <template #source> diff --git a/app/assets/javascripts/diffs/components/diff_content.vue b/app/assets/javascripts/diffs/components/diff_content.vue index 9ecb9a44443..e68260b3e62 100644 --- a/app/assets/javascripts/diffs/components/diff_content.vue +++ b/app/assets/javascripts/diffs/components/diff_content.vue @@ -85,11 +85,9 @@ export default { }, }, updated() { - if (window.gon?.features?.codeNavigation) { - this.$nextTick(() => { - eventHub.$emit('showBlobInteractionZones', this.diffFile.new_path); - }); - } + this.$nextTick(() => { + eventHub.$emit('showBlobInteractionZones', this.diffFile.new_path); + }); }, methods: { ...mapActions('diffs', ['saveDiffDiscussion', 'closeDiffFileCommentForm']), diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index 02396a4ba1b..529723a349d 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -44,7 +44,7 @@ export default { return { isLoadingCollapsedDiff: false, forkMessageVisible: false, - isCollapsed: this.file.viewer.collapsed || false, + isCollapsed: this.file.viewer.automaticallyCollapsed || false, }; }, computed: { @@ -96,16 +96,16 @@ export default { }, 'file.file_hash': { handler: function watchFileHash() { - if (this.viewDiffsFileByFile && this.file.viewer.collapsed) { + if (this.viewDiffsFileByFile && this.file.viewer.automaticallyCollapsed) { this.isCollapsed = false; this.handleLoadCollapsedDiff(); } else { - this.isCollapsed = this.file.viewer.collapsed || false; + this.isCollapsed = this.file.viewer.automaticallyCollapsed || false; } }, immediate: true, }, - 'file.viewer.collapsed': function setIsCollapsed(newVal) { + 'file.viewer.automaticallyCollapsed': function setIsCollapsed(newVal) { if (!this.viewDiffsFileByFile) { this.isCollapsed = newVal; } diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue index fded391cc84..b08b9df13a4 100644 --- a/app/assets/javascripts/diffs/components/diff_file_header.vue +++ b/app/assets/javascripts/diffs/components/diff_file_header.vue @@ -1,39 +1,44 @@ <script> -/* eslint-disable vue/no-v-html */ import { escape } from 'lodash'; import { mapActions, mapGetters } from 'vuex'; import { - GlDeprecatedButton, GlTooltipDirective, GlSafeHtmlDirective, - GlLoadingIcon, GlIcon, GlButton, + GlButtonGroup, + GlDropdown, + GlDropdownItem, + GlDropdownDivider, } from '@gitlab/ui'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import FileIcon from '~/vue_shared/components/file_icon.vue'; import { truncateSha } from '~/lib/utils/text_utility'; import { __, s__, sprintf } from '~/locale'; import { diffViewerModes } from '~/ide/constants'; -import EditButton from './edit_button.vue'; import DiffStats from './diff_stats.vue'; import { scrollToElement } from '~/lib/utils/common_utils'; +import { DIFF_FILE_HEADER } from '../i18n'; export default { components: { - GlLoadingIcon, - GlDeprecatedButton, ClipboardButton, - EditButton, GlIcon, FileIcon, DiffStats, GlButton, + GlButtonGroup, + GlDropdown, + GlDropdownItem, + GlDropdownDivider, }, directives: { GlTooltip: GlTooltipDirective, SafeHtml: GlSafeHtmlDirective, }, + i18n: { + ...DIFF_FILE_HEADER, + }, props: { discussionPath: { type: String, @@ -69,6 +74,11 @@ export default { default: false, }, }, + data() { + return { + moreActionsShown: false, + }; + }, computed: { ...mapGetters('diffs', ['diffHasExpandedDiscussions', 'diffHasDiscussions']), diffContentIDSelector() { @@ -128,13 +138,9 @@ export default { }, viewReplacedFileButtonText() { const truncatedBaseSha = escape(truncateSha(this.diffFile.diff_refs.base_sha)); - return sprintf( - s__('MergeRequests|View replaced file @ %{commitId}'), - { - commitId: `<span class="commit-sha">${truncatedBaseSha}</span>`, - }, - false, - ); + return sprintf(s__('MergeRequests|View replaced file @ %{commitId}'), { + commitId: truncatedBaseSha, + }); }, gfmCopyText() { return `\`${this.diffFile.file_path}\``; @@ -151,6 +157,13 @@ export default { } return s__('MRDiff|Show full file'); }, + showEditButton() { + return ( + this.diffFile.blob?.readable_text && + !this.diffFile.deleted_file && + (this.diffFile.edit_path || this.diffFile.ide_edit_path) + ); + }, }, methods: { ...mapActions('diffs', [ @@ -162,8 +175,11 @@ export default { handleToggleFile() { this.$emit('toggleFile'); }, - showForkMessage() { - this.$emit('showForkMessage'); + showForkMessage(e) { + if (this.canCurrentUserFork && !this.diffFile.can_modify_blob) { + e.preventDefault(); + this.$emit('showForkMessage'); + } }, handleFileNameClick(e) { const isLinkToOtherPage = @@ -179,6 +195,9 @@ export default { } } }, + setMoreActionsShown(val) { + this.moreActionsShown = val; + }, }, }; </script> @@ -186,10 +205,11 @@ export default { <template> <div ref="header" + :class="{ 'gl-z-dropdown-menu!': moreActionsShown }" class="js-file-title file-title file-title-flex-parent" @click.self="handleToggleFile" > - <div class="file-header-content"> + <div class="file-header-content gl-display-flex gl-align-items-center gl-pr-0!"> <gl-icon v-if="collapsible" ref="collapseIcon" @@ -202,7 +222,7 @@ export default { <a ref="titleWrapper" :v-once="!viewDiffsFileByFile" - class="gl-mr-2" + class="gl-mr-2 gl-text-decoration-none!" :href="titleLink" @click="handleFileNameClick" > @@ -210,20 +230,27 @@ export default { <span v-if="isFileRenamed"> <strong v-gl-tooltip + v-safe-html="diffFile.old_path_html" :title="diffFile.old_path" class="file-title-name" - v-html="diffFile.old_path_html" ></strong> → <strong v-gl-tooltip + v-safe-html="diffFile.new_path_html" :title="diffFile.new_path" class="file-title-name" - v-html="diffFile.new_path_html" ></strong> </span> - <strong v-else v-gl-tooltip :title="filePath" class="file-title-name" data-container="body"> + <strong + v-else + v-gl-tooltip + :title="filePath" + class="file-title-name" + data-container="body" + data-qa-selector="file_name_content" + > {{ filePath }} </strong> </a> @@ -232,7 +259,8 @@ export default { :title="__('Copy file path')" :text="diffFile.file_path" :gfm="gfmCopyText" - css-class="btn-default btn-transparent btn-clipboard" + data-testid="diff-file-copy-clipboard" + category="tertiary" data-track-event="click_copy_file_button" data-track-label="diff_copy_file_path_button" data-track-property="diff_copy_file" @@ -247,93 +275,93 @@ export default { <div v-if="!diffFile.submodule && addMergeRequestButtons" - class="file-actions d-none d-sm-flex align-items-center flex-wrap" + class="file-actions d-flex align-items-center flex-wrap" > <diff-stats :added-lines="diffFile.added_lines" :removed-lines="diffFile.removed_lines" /> - <div class="btn-group" role="group"> - <template v-if="diffFile.blob && diffFile.blob.readable_text"> - <span v-gl-tooltip.hover :title="s__('MergeRequests|Toggle comments for this file')"> - <gl-deprecated-button - ref="toggleDiscussionsButton" - :disabled="!diffHasDiscussions(diffFile)" - :class="{ active: diffHasExpandedDiscussions(diffFile) }" - class="js-btn-vue-toggle-comments btn" - data-qa-selector="toggle_comments_button" - data-track-event="click_toggle_comments_button" - data-track-label="diff_toggle_comments_button" - data-track-property="diff_toggle_comments" - type="button" - @click="toggleFileDiscussionWrappers(diffFile)" - > - <gl-icon name="comment" /> - </gl-deprecated-button> - </span> - - <edit-button - v-if="!diffFile.deleted_file" - :can-current-user-fork="canCurrentUserFork" - :edit-path="diffFile.edit_path" - :can-modify-blob="diffFile.can_modify_blob" - data-track-event="click_toggle_edit_button" - data-track-label="diff_toggle_edit_button" - data-track-property="diff_toggle_edit" - @showForkMessage="showForkMessage" - /> - </template> - - <a - v-if="diffFile.replaced_view_path" - ref="replacedFileButton" - :href="diffFile.replaced_view_path" - class="btn view-file" - v-html="viewReplacedFileButtonText" - > - </a> - <gl-deprecated-button - v-if="!diffFile.is_fully_expanded" - ref="expandDiffToFullFileButton" - v-gl-tooltip.hover - :title="expandDiffToFullFileTitle" - class="expand-file" - data-track-event="click_toggle_view_full_button" - data-track-label="diff_toggle_view_full_button" - data-track-property="diff_toggle_view_full" - @click="toggleFullDiff(diffFile.file_path)" - > - <gl-loading-icon v-if="diffFile.isLoadingFullFile" color="dark" inline /> - <gl-icon v-else-if="diffFile.isShowingFullFile" name="doc-changes" /> - <gl-icon v-else name="doc-expand" /> - </gl-deprecated-button> - <gl-deprecated-button - ref="viewButton" - v-gl-tooltip.hover - :href="diffFile.view_path" - target="_blank" - class="view-file" - data-track-event="click_toggle_view_sha_button" - data-track-label="diff_toggle_view_sha_button" - data-track-property="diff_toggle_view_sha" - :title="viewFileButtonText" - > - <gl-icon name="doc-text" /> - </gl-deprecated-button> - - <a + <gl-button-group class="gl-pt-0!"> + <gl-button v-if="diffFile.external_url" ref="externalLink" v-gl-tooltip.hover :href="diffFile.external_url" :title="`View on ${diffFile.formatted_external_url}`" target="_blank" - rel="noopener noreferrer" data-track-event="click_toggle_external_button" data-track-label="diff_toggle_external_button" data-track-property="diff_toggle_external" - class="btn btn-file-option" + icon="external-link" + /> + <gl-dropdown + v-gl-tooltip.hover.focus="$options.i18n.optionsDropdownTitle" + right + toggle-class="btn-icon js-diff-more-actions" + class="gl-pt-0!" + @show="setMoreActionsShown(true)" + @hidden="setMoreActionsShown(false)" > - <gl-icon name="external-link" /> - </a> - </div> + <template #button-content> + <gl-icon name="ellipsis_v" class="mr-0" /> + <span class="sr-only">{{ $options.i18n.optionsDropdownTitle }}</span> + </template> + <gl-dropdown-item + v-if="diffFile.replaced_view_path" + ref="replacedFileButton" + :href="diffFile.replaced_view_path" + target="_blank" + > + {{ viewReplacedFileButtonText }} + </gl-dropdown-item> + <gl-dropdown-item ref="viewButton" :href="diffFile.view_path" target="_blank"> + {{ viewFileButtonText }} + </gl-dropdown-item> + <template v-if="showEditButton"> + <gl-dropdown-item + v-if="diffFile.edit_path" + ref="editButton" + :href="diffFile.edit_path" + class="js-edit-blob" + @click="showForkMessage" + > + {{ __('Edit in single-file editor') }} + </gl-dropdown-item> + <gl-dropdown-item + v-if="diffFile.edit_path" + ref="ideEditButton" + :href="diffFile.ide_edit_path" + class="js-ide-edit-blob" + > + {{ __('Edit in Web IDE') }} + </gl-dropdown-item> + </template> + + <template v-if="!diffFile.viewer.automaticallyCollapsed"> + <gl-dropdown-divider + v-if="!diffFile.is_fully_expanded || diffHasDiscussions(diffFile)" + /> + + <gl-dropdown-item + v-if="diffHasDiscussions(diffFile)" + ref="toggleDiscussionsButton" + data-qa-selector="toggle_comments_button" + @click="toggleFileDiscussionWrappers(diffFile)" + > + <template v-if="diffHasExpandedDiscussions(diffFile)"> + {{ __('Hide comments on this file') }} + </template> + <template v-else> + {{ __('Show comments on this file') }} + </template> + </gl-dropdown-item> + <gl-dropdown-item + v-if="!diffFile.is_fully_expanded" + ref="expandDiffToFullFileButton" + @click="toggleFullDiff(diffFile.file_path)" + > + {{ expandDiffToFullFileTitle }} + </gl-dropdown-item> + </template> + </gl-dropdown> + </gl-button-group> </div> <div diff --git a/app/assets/javascripts/diffs/components/diff_row_utils.js b/app/assets/javascripts/diffs/components/diff_row_utils.js new file mode 100644 index 00000000000..08b87a4bade --- /dev/null +++ b/app/assets/javascripts/diffs/components/diff_row_utils.js @@ -0,0 +1,85 @@ +import { __ } from '~/locale'; +import { + MATCH_LINE_TYPE, + CONTEXT_LINE_TYPE, + LINE_HOVER_CLASS_NAME, + OLD_NO_NEW_LINE_TYPE, + NEW_NO_NEW_LINE_TYPE, + EMPTY_CELL_TYPE, +} from '../constants'; + +export const isHighlighted = (state, line, isCommented) => { + if (isCommented) return true; + + const lineCode = line?.line_code; + return lineCode ? lineCode === state.diffs.highlightedRow : false; +}; + +export const isContextLine = type => type === CONTEXT_LINE_TYPE; + +export const isMatchLine = type => type === MATCH_LINE_TYPE; + +export const isMetaLine = type => + [OLD_NO_NEW_LINE_TYPE, NEW_NO_NEW_LINE_TYPE, EMPTY_CELL_TYPE].includes(type); + +export const shouldRenderCommentButton = (isLoggedIn, isCommentButtonRendered) => { + return isCommentButtonRendered && isLoggedIn; +}; + +export const hasDiscussions = line => line?.discussions?.length > 0; + +export const lineHref = line => `#${line?.line_code || ''}`; + +export const lineCode = line => { + if (!line) return undefined; + return line.line_code || line.left?.line_code || line.right?.line_code; +}; + +export const classNameMapCell = (line, hll, isLoggedIn, isHover) => { + if (!line) return []; + const { type } = line; + + return [ + type, + { + hll, + [LINE_HOVER_CLASS_NAME]: isLoggedIn && isHover && !isContextLine(type) && !isMetaLine(type), + }, + ]; +}; + +export const addCommentTooltip = line => { + let tooltip; + if (!line) return tooltip; + + tooltip = __('Add a comment to this line'); + const brokenSymlinks = line.commentsDisabled; + + if (brokenSymlinks) { + if (brokenSymlinks.wasSymbolic || brokenSymlinks.isSymbolic) { + tooltip = __( + 'Commenting on symbolic links that replace or are replaced by files is currently not supported.', + ); + } else if (brokenSymlinks.wasReal || brokenSymlinks.isReal) { + tooltip = __( + 'Commenting on files that replace or are replaced by symbolic links is currently not supported.', + ); + } + } + + return tooltip; +}; + +export const parallelViewLeftLineType = (line, hll) => { + if (line?.right?.type === NEW_NO_NEW_LINE_TYPE) { + return OLD_NO_NEW_LINE_TYPE; + } + + const lineTypeClass = line?.left ? line.left.type : EMPTY_CELL_TYPE; + + return [lineTypeClass, { hll }]; +}; + +export const shouldShowCommentButton = (hover, context, meta, discussions) => { + return hover && !context && !meta && !discussions; +}; diff --git a/app/assets/javascripts/diffs/components/diff_stats.vue b/app/assets/javascripts/diffs/components/diff_stats.vue index 05fbbd39fae..f229fc4cf60 100644 --- a/app/assets/javascripts/diffs/components/diff_stats.vue +++ b/app/assets/javascripts/diffs/components/diff_stats.vue @@ -42,7 +42,7 @@ export default { class="diff-stats" :class="{ 'is-compare-versions-header d-none d-lg-inline-flex': isCompareVersionsHeader, - 'd-inline-flex': !isCompareVersionsHeader, + 'd-none d-sm-inline-flex': !isCompareVersionsHeader, }" > <div v-if="hasDiffFiles" class="diff-stats-group"> diff --git a/app/assets/javascripts/diffs/components/diff_table_cell.vue b/app/assets/javascripts/diffs/components/diff_table_cell.vue deleted file mode 100644 index 49982a81372..00000000000 --- a/app/assets/javascripts/diffs/components/diff_table_cell.vue +++ /dev/null @@ -1,206 +0,0 @@ -<script> -import { mapGetters, mapActions } from 'vuex'; -import { GlIcon, GlTooltipDirective } from '@gitlab/ui'; -import { getParameterByName, parseBoolean } from '~/lib/utils/common_utils'; -import DiffGutterAvatars from './diff_gutter_avatars.vue'; -import { __ } from '~/locale'; -import { - CONTEXT_LINE_TYPE, - LINE_POSITION_RIGHT, - EMPTY_CELL_TYPE, - OLD_NO_NEW_LINE_TYPE, - OLD_LINE_TYPE, - NEW_NO_NEW_LINE_TYPE, - LINE_HOVER_CLASS_NAME, -} from '../constants'; - -export default { - components: { - DiffGutterAvatars, - GlIcon, - }, - directives: { - GlTooltip: GlTooltipDirective, - }, - props: { - line: { - type: Object, - required: true, - }, - fileHash: { - type: String, - required: true, - }, - isHighlighted: { - type: Boolean, - required: true, - }, - showCommentButton: { - type: Boolean, - required: false, - default: false, - }, - linePosition: { - type: String, - required: false, - default: '', - }, - lineType: { - type: String, - required: false, - default: '', - }, - isBottom: { - type: Boolean, - required: false, - default: false, - }, - isHover: { - type: Boolean, - required: false, - default: false, - }, - }, - data() { - return { - isCommentButtonRendered: false, - }; - }, - computed: { - ...mapGetters(['isLoggedIn']), - lineCode() { - return ( - this.line.line_code || - (this.line.left && this.line.left.line_code) || - (this.line.right && this.line.right.line_code) - ); - }, - lineHref() { - return `#${this.line.line_code || ''}`; - }, - shouldShowCommentButton() { - return this.isHover && !this.isContextLine && !this.isMetaLine && !this.hasDiscussions; - }, - hasDiscussions() { - return this.line.discussions && this.line.discussions.length > 0; - }, - shouldShowAvatarsOnGutter() { - if (!this.line.type && this.linePosition === LINE_POSITION_RIGHT) { - return false; - } - return this.showCommentButton && this.hasDiscussions; - }, - shouldRenderCommentButton() { - if (!this.isCommentButtonRendered) { - return false; - } - - if (this.isLoggedIn && this.showCommentButton) { - const isDiffHead = parseBoolean(getParameterByName('diff_head')); - return !isDiffHead || gon.features?.mergeRefHeadComments; - } - - return false; - }, - isContextLine() { - return this.line.type === CONTEXT_LINE_TYPE; - }, - isMetaLine() { - const { type } = this.line; - - return ( - type === OLD_NO_NEW_LINE_TYPE || type === NEW_NO_NEW_LINE_TYPE || type === EMPTY_CELL_TYPE - ); - }, - classNameMap() { - const { type } = this.line; - - return [ - type, - { - hll: this.isHighlighted, - [LINE_HOVER_CLASS_NAME]: - this.isLoggedIn && this.isHover && !this.isContextLine && !this.isMetaLine, - }, - ]; - }, - lineNumber() { - return this.lineType === OLD_LINE_TYPE ? this.line.old_line : this.line.new_line; - }, - addCommentTooltip() { - const brokenSymlinks = this.line.commentsDisabled; - let tooltip = __('Add a comment to this line'); - - if (brokenSymlinks) { - if (brokenSymlinks.wasSymbolic || brokenSymlinks.isSymbolic) { - tooltip = __( - 'Commenting on symbolic links that replace or are replaced by files is currently not supported.', - ); - } else if (brokenSymlinks.wasReal || brokenSymlinks.isReal) { - tooltip = __( - 'Commenting on files that replace or are replaced by symbolic links is currently not supported.', - ); - } - } - - return tooltip; - }, - }, - mounted() { - this.unwatchShouldShowCommentButton = this.$watch('shouldShowCommentButton', newVal => { - if (newVal) { - this.isCommentButtonRendered = true; - this.unwatchShouldShowCommentButton(); - } - }); - }, - beforeDestroy() { - this.unwatchShouldShowCommentButton(); - }, - methods: { - ...mapActions('diffs', ['showCommentForm', 'setHighlightedRow', 'toggleLineDiscussions']), - handleCommentButton() { - this.showCommentForm({ lineCode: this.line.line_code, fileHash: this.fileHash }); - }, - }, -}; -</script> - -<template> - <td ref="td" :class="classNameMap"> - <span - ref="addNoteTooltip" - v-gl-tooltip - class="add-diff-note tooltip-wrapper" - :title="addCommentTooltip" - > - <button - v-if="shouldRenderCommentButton" - v-show="shouldShowCommentButton" - ref="addDiffNoteButton" - type="button" - class="add-diff-note note-button js-add-diff-note-button qa-diff-comment" - :disabled="line.commentsDisabled" - @click="handleCommentButton" - > - <gl-icon :size="12" name="comment" /> - </button> - </span> - <a - v-if="lineNumber" - ref="lineNumberRef" - :data-linenumber="lineNumber" - :href="lineHref" - @click="setHighlightedRow(lineCode)" - > - </a> - <diff-gutter-avatars - v-if="shouldShowAvatarsOnGutter" - :discussions="line.discussions" - :discussions-expanded="line.discussionsExpanded" - @toggleLineDiscussions=" - toggleLineDiscussions({ lineCode, fileHash, expanded: !line.discussionsExpanded }) - " - /> - </td> -</template> diff --git a/app/assets/javascripts/diffs/components/edit_button.vue b/app/assets/javascripts/diffs/components/edit_button.vue deleted file mode 100644 index ff1af5569dc..00000000000 --- a/app/assets/javascripts/diffs/components/edit_button.vue +++ /dev/null @@ -1,64 +0,0 @@ -<script> -import { GlTooltipDirective, GlDeprecatedButton, GlIcon } from '@gitlab/ui'; -import { __ } from '~/locale'; - -export default { - components: { - GlDeprecatedButton, - GlIcon, - }, - directives: { - GlTooltip: GlTooltipDirective, - }, - props: { - editPath: { - type: String, - required: false, - default: '', - }, - canCurrentUserFork: { - type: Boolean, - required: true, - }, - canModifyBlob: { - type: Boolean, - required: false, - default: false, - }, - }, - computed: { - tooltipTitle() { - if (this.isDisabled) { - return __("Can't edit as source branch was deleted"); - } - - return __('Edit file'); - }, - isDisabled() { - return !this.editPath; - }, - }, - methods: { - handleEditClick(evt) { - if (this.canCurrentUserFork && !this.canModifyBlob) { - evt.preventDefault(); - this.$emit('showForkMessage'); - } - }, - }, -}; -</script> - -<template> - <span v-gl-tooltip.top :title="tooltipTitle"> - <gl-deprecated-button - :href="editPath" - :disabled="isDisabled" - :class="{ 'cursor-not-allowed': isDisabled }" - class="rounded-0 js-edit-blob" - @click.native="handleEditClick" - > - <gl-icon name="pencil" /> - </gl-deprecated-button> - </span> -</template> diff --git a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue index 7fab750089e..99cf79a70d4 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue @@ -1,22 +1,9 @@ <script> import { mapActions, mapGetters, mapState } from 'vuex'; import { GlTooltipDirective, GlIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui'; -import { - MATCH_LINE_TYPE, - NEW_LINE_TYPE, - OLD_LINE_TYPE, - CONTEXT_LINE_TYPE, - CONTEXT_LINE_CLASS_NAME, - LINE_POSITION_LEFT, - LINE_POSITION_RIGHT, - LINE_HOVER_CLASS_NAME, - OLD_NO_NEW_LINE_TYPE, - NEW_NO_NEW_LINE_TYPE, - EMPTY_CELL_TYPE, -} from '../constants'; -import { __ } from '~/locale'; -import { getParameterByName, parseBoolean } from '~/lib/utils/common_utils'; +import { CONTEXT_LINE_CLASS_NAME } from '../constants'; import DiffGutterAvatars from './diff_gutter_avatars.vue'; +import * as utils from './diff_row_utils'; export default { components: { @@ -61,14 +48,11 @@ export default { ...mapGetters('diffs', ['fileLineCoverage']), ...mapState({ isHighlighted(state) { - if (this.isCommented) return true; - - const lineCode = this.line.line_code; - return lineCode ? lineCode === state.diffs.highlightedRow : false; + return utils.isHighlighted(state, this.line, this.isCommented); }, }), isContextLine() { - return this.line.type === CONTEXT_LINE_TYPE; + return utils.isContextLine(this.line.type); }, classNameMap() { return [ @@ -82,82 +66,44 @@ export default { return this.line.line_code || `${this.fileHash}_${this.line.old_line}_${this.line.new_line}`; }, isMatchLine() { - return this.line.type === MATCH_LINE_TYPE; + return utils.isMatchLine(this.line.type); }, coverageState() { return this.fileLineCoverage(this.filePath, this.line.new_line); }, isMetaLine() { - const { type } = this.line; - - return ( - type === OLD_NO_NEW_LINE_TYPE || type === NEW_NO_NEW_LINE_TYPE || type === EMPTY_CELL_TYPE - ); + return utils.isMetaLine(this.line.type); }, classNameMapCell() { - const { type } = this.line; - - return [ - type, - { - hll: this.isHighlighted, - [LINE_HOVER_CLASS_NAME]: - this.isLoggedIn && this.isHover && !this.isContextLine && !this.isMetaLine, - }, - ]; + return utils.classNameMapCell(this.line, this.isHighlighted, this.isLoggedIn, this.isHover); }, addCommentTooltip() { - const brokenSymlinks = this.line.commentsDisabled; - let tooltip = __('Add a comment to this line'); - - if (brokenSymlinks) { - if (brokenSymlinks.wasSymbolic || brokenSymlinks.isSymbolic) { - tooltip = __( - 'Commenting on symbolic links that replace or are replaced by files is currently not supported.', - ); - } else if (brokenSymlinks.wasReal || brokenSymlinks.isReal) { - tooltip = __( - 'Commenting on files that replace or are replaced by symbolic links is currently not supported.', - ); - } - } - - return tooltip; + return utils.addCommentTooltip(this.line); }, shouldRenderCommentButton() { - if (this.isLoggedIn) { - const isDiffHead = parseBoolean(getParameterByName('diff_head')); - return !isDiffHead || gon.features?.mergeRefHeadComments; - } - - return false; + return utils.shouldRenderCommentButton(this.isLoggedIn, true); }, shouldShowCommentButton() { - return this.isHover && !this.isContextLine && !this.isMetaLine && !this.hasDiscussions; + return utils.shouldShowCommentButton( + this.isHover, + this.isContextLine, + this.isMetaLine, + this.hasDiscussions, + ); }, hasDiscussions() { - return this.line.discussions && this.line.discussions.length > 0; + return utils.hasDiscussions(this.line); }, lineHref() { - return `#${this.line.line_code || ''}`; + return utils.lineHref(this.line); }, lineCode() { - return ( - this.line.line_code || - (this.line.left && this.line.left.line_code) || - (this.line.right && this.line.right.line_code) - ); + return utils.lineCode(this.line); }, shouldShowAvatarsOnGutter() { return this.hasDiscussions; }, }, - created() { - this.newLineType = NEW_LINE_TYPE; - this.oldLineType = OLD_LINE_TYPE; - this.linePositionLeft = LINE_POSITION_LEFT; - this.linePositionRight = LINE_POSITION_RIGHT; - }, mounted() { this.scrollToLineIfNeededInline(this.line); }, @@ -242,6 +188,7 @@ export default { class="line-coverage" ></td> <td + :key="line.line_code" v-safe-html="line.rich_text" :class="[ line.type, diff --git a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue index b525490f7cc..127e3f214cf 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue @@ -113,8 +113,8 @@ export default { }, methods: { ...mapActions('diffs', ['showCommentForm']), - showNewDiscussionForm() { - this.showCommentForm({ lineCode: this.line.line_code, fileHash: this.diffFileHash }); + showNewDiscussionForm(lineCode) { + this.showCommentForm({ lineCode, fileHash: this.diffFileHash }); }, }, }; @@ -134,7 +134,7 @@ export default { v-if="!hasDraftLeft" :has-form="showLeftSideCommentForm" :render-reply-placeholder="shouldRenderReplyPlaceholderOnLeft" - @showNewDiscussionForm="showNewDiscussionForm" + @showNewDiscussionForm="showNewDiscussionForm(line.left.line_code)" > <template #form> <diff-line-note-form @@ -159,7 +159,7 @@ export default { v-if="!hasDraftRight" :has-form="showRightSideCommentForm" :render-reply-placeholder="shouldRenderReplyPlaceholderOnRight" - @showNewDiscussionForm="showNewDiscussionForm" + @showNewDiscussionForm="showNewDiscussionForm(line.right.line_code)" > <template #form> <diff-line-note-form diff --git a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue index 0bf47dc77a6..cdc6db791f0 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue @@ -2,21 +2,9 @@ import { mapActions, mapGetters, mapState } from 'vuex'; import $ from 'jquery'; import { GlTooltipDirective, GlIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui'; -import { - MATCH_LINE_TYPE, - NEW_LINE_TYPE, - OLD_LINE_TYPE, - CONTEXT_LINE_TYPE, - CONTEXT_LINE_CLASS_NAME, - OLD_NO_NEW_LINE_TYPE, - PARALLEL_DIFF_VIEW_TYPE, - NEW_NO_NEW_LINE_TYPE, - EMPTY_CELL_TYPE, - LINE_HOVER_CLASS_NAME, -} from '../constants'; -import { __ } from '~/locale'; -import { getParameterByName, parseBoolean } from '~/lib/utils/common_utils'; +import { CONTEXT_LINE_CLASS_NAME, PARALLEL_DIFF_VIEW_TYPE } from '../constants'; import DiffGutterAvatars from './diff_gutter_avatars.vue'; +import * as utils from './diff_row_utils'; export default { components: { @@ -63,20 +51,15 @@ export default { ...mapGetters(['isLoggedIn']), ...mapState({ isHighlighted(state) { - if (this.isCommented) return true; - - const lineCode = - (this.line.left && this.line.left.line_code) || - (this.line.right && this.line.right.line_code); - - return lineCode ? lineCode === state.diffs.highlightedRow : false; + const line = this.line.left?.line_code ? this.line.left : this.line.right; + return utils.isHighlighted(state, line, this.isCommented); }, }), isContextLineLeft() { - return this.line.left && this.line.left.type === CONTEXT_LINE_TYPE; + return utils.isContextLine(this.line.left?.type); }, isContextLineRight() { - return this.line.right && this.line.right.type === CONTEXT_LINE_TYPE; + return utils.isContextLine(this.line.right?.type); }, classNameMap() { return { @@ -85,157 +68,80 @@ export default { }; }, parallelViewLeftLineType() { - if (this.line.right && this.line.right.type === NEW_NO_NEW_LINE_TYPE) { - return OLD_NO_NEW_LINE_TYPE; - } - - const lineTypeClass = this.line.left ? this.line.left.type : EMPTY_CELL_TYPE; - - return [ - lineTypeClass, - { - hll: this.isHighlighted, - }, - ]; + return utils.parallelViewLeftLineType(this.line, this.isHighlighted); }, isMatchLineLeft() { - return this.line.left && this.line.left.type === MATCH_LINE_TYPE; + return utils.isMatchLine(this.line.left?.type); }, isMatchLineRight() { - return this.line.right && this.line.right.type === MATCH_LINE_TYPE; + return utils.isMatchLine(this.line.right?.type); }, coverageState() { return this.fileLineCoverage(this.filePath, this.line.right.new_line); }, classNameMapCellLeft() { - const { type } = this.line.left; - - return [ - type, - { - hll: this.isHighlighted, - [LINE_HOVER_CLASS_NAME]: - this.isLoggedIn && this.isLeftHover && !this.isContextLineLeft && !this.isMetaLineLeft, - }, - ]; + return utils.classNameMapCell( + this.line.left, + this.isHighlighted, + this.isLoggedIn, + this.isLeftHover, + ); }, classNameMapCellRight() { - const { type } = this.line.right; - - return [ - type, - { - hll: this.isHighlighted, - [LINE_HOVER_CLASS_NAME]: - this.isLoggedIn && - this.isRightHover && - !this.isContextLineRight && - !this.isMetaLineRight, - }, - ]; + return utils.classNameMapCell( + this.line.right, + this.isHighlighted, + this.isLoggedIn, + this.isRightHover, + ); }, addCommentTooltipLeft() { - const brokenSymlinks = this.line.left.commentsDisabled; - let tooltip = __('Add a comment to this line'); - - if (brokenSymlinks) { - if (brokenSymlinks.wasSymbolic || brokenSymlinks.isSymbolic) { - tooltip = __( - 'Commenting on symbolic links that replace or are replaced by files is currently not supported.', - ); - } else if (brokenSymlinks.wasReal || brokenSymlinks.isReal) { - tooltip = __( - 'Commenting on files that replace or are replaced by symbolic links is currently not supported.', - ); - } - } - - return tooltip; + return utils.addCommentTooltip(this.line.left); }, addCommentTooltipRight() { - const brokenSymlinks = this.line.right.commentsDisabled; - let tooltip = __('Add a comment to this line'); - - if (brokenSymlinks) { - if (brokenSymlinks.wasSymbolic || brokenSymlinks.isSymbolic) { - tooltip = __( - 'Commenting on symbolic links that replace or are replaced by files is currently not supported.', - ); - } else if (brokenSymlinks.wasReal || brokenSymlinks.isReal) { - tooltip = __( - 'Commenting on files that replace or are replaced by symbolic links is currently not supported.', - ); - } - } - - return tooltip; + return utils.addCommentTooltip(this.line.right); }, shouldRenderCommentButton() { - if (!this.isCommentButtonRendered) { - return false; - } - - if (this.isLoggedIn) { - const isDiffHead = parseBoolean(getParameterByName('diff_head')); - return !isDiffHead || gon.features?.mergeRefHeadComments; - } - - return false; + return utils.shouldRenderCommentButton(this.isLoggedIn, this.isCommentButtonRendered); }, shouldShowCommentButtonLeft() { - return ( - this.isLeftHover && - !this.isContextLineLeft && - !this.isMetaLineLeft && - !this.hasDiscussionsLeft + return utils.shouldShowCommentButton( + this.isLeftHover, + this.isContextLineLeft, + this.isMetaLineLeft, + this.hasDiscussionsLeft, ); }, shouldShowCommentButtonRight() { - return ( - this.isRightHover && - !this.isContextLineRight && - !this.isMetaLineRight && - !this.hasDiscussionsRight + return utils.shouldShowCommentButton( + this.isRightHover, + this.isContextLineRight, + this.isMetaLineRight, + this.hasDiscussionsRight, ); }, hasDiscussionsLeft() { - return this.line.left?.discussions?.length > 0; + return utils.hasDiscussions(this.line.left); }, hasDiscussionsRight() { - return this.line.right?.discussions?.length > 0; + return utils.hasDiscussions(this.line.right); }, lineHrefOld() { - return `#${this.line.left.line_code || ''}`; + return utils.lineHref(this.line.left); }, lineHrefNew() { - return `#${this.line.right.line_code || ''}`; + return utils.lineHref(this.line.right); }, lineCode() { - return ( - (this.line.left && this.line.left.line_code) || - (this.line.right && this.line.right.line_code) - ); + return utils.lineCode(this.line); }, isMetaLineLeft() { - const type = this.line.left?.type; - - return ( - type === OLD_NO_NEW_LINE_TYPE || type === NEW_NO_NEW_LINE_TYPE || type === EMPTY_CELL_TYPE - ); + return utils.isMetaLine(this.line.left?.type); }, isMetaLineRight() { - const type = this.line.right?.type; - - return ( - type === OLD_NO_NEW_LINE_TYPE || type === NEW_NO_NEW_LINE_TYPE || type === EMPTY_CELL_TYPE - ); + return utils.isMetaLine(this.line.right?.type); }, }, - created() { - this.newLineType = NEW_LINE_TYPE; - this.oldLineType = OLD_LINE_TYPE; - this.parallelDiffViewType = PARALLEL_DIFF_VIEW_TYPE; - }, mounted() { this.scrollToLineIfNeededParallel(this.line); this.unwatchShouldShowCommentButton = this.$watch( @@ -341,6 +247,7 @@ export default { <td :class="parallelViewLeftLineType" class="line-coverage left-side"></td> <td :id="line.left.line_code" + :key="line.left.line_code" v-safe-html="line.left.rich_text" :class="parallelViewLeftLineType" class="line_content with-coverage parallel left-side" @@ -401,6 +308,7 @@ export default { ></td> <td :id="line.right.line_code" + :key="line.right.rich_text" v-safe-html="line.right.rich_text" :class="[ line.right.type, diff --git a/app/assets/javascripts/diffs/diff_file.js b/app/assets/javascripts/diffs/diff_file.js index 610b71235d9..933197a2c7f 100644 --- a/app/assets/javascripts/diffs/diff_file.js +++ b/app/assets/javascripts/diffs/diff_file.js @@ -18,9 +18,21 @@ function fileSymlinkInformation(file, fileList) { ); } +function collapsed(file) { + const viewer = file.viewer || {}; + + return { + automaticallyCollapsed: viewer.automaticallyCollapsed || viewer.collapsed || false, + }; +} + export function prepareRawDiffFile({ file, allFiles }) { Object.assign(file, { brokenSymlink: fileSymlinkInformation(file, allFiles), + viewer: { + ...file.viewer, + ...collapsed(file), + }, }); return file; diff --git a/app/assets/javascripts/diffs/i18n.js b/app/assets/javascripts/diffs/i18n.js new file mode 100644 index 00000000000..8699cd88a18 --- /dev/null +++ b/app/assets/javascripts/diffs/i18n.js @@ -0,0 +1,5 @@ +import { __ } from '~/locale'; + +export const DIFF_FILE_HEADER = { + optionsDropdownTitle: __('Options'), +}; diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index 0f275f1cb3e..966b706fc31 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -103,7 +103,7 @@ export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => { commit(types.VIEW_DIFF_FILE, state.diffFiles[0].file_hash); } - if (gon.features?.codeNavigation) { + if (state.diffFiles?.length) { // eslint-disable-next-line promise/catch-or-return,promise/no-nesting import('~/code_navigation').then(m => m.default({ @@ -236,7 +236,7 @@ export const renderFileForDiscussionId = ({ commit, rootState, state }, discussi commit(types.RENDER_FILE, file); } - if (file.viewer.collapsed) { + if (file.viewer.automaticallyCollapsed) { eventHub.$emit(`loadCollapsedDiff/${file.file_hash}`); scrollToElement(document.getElementById(file.file_hash)); } else { @@ -252,7 +252,8 @@ export const startRenderDiffsQueue = ({ state, commit }) => { const nextFile = state.diffFiles.find( file => !file.renderIt && - (file.viewer && (!file.viewer.collapsed || file.viewer.name !== diffViewerModes.text)), + (file.viewer && + (!file.viewer.automaticallyCollapsed || file.viewer.name !== diffViewerModes.text)), ); if (nextFile) { @@ -631,7 +632,7 @@ export function switchToFullDiffFromRenamedFile({ commit, dispatch, state }, { d filePath: diffFile.file_path, viewer: { ...diffFile.alternate_viewer, - collapsed: false, + automaticallyCollapsed: false, }, }); commit(types.SET_CURRENT_VIEW_DIFF_FILE_LINES, { filePath: diffFile.file_path, lines }); diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js index 42df5873a41..91425c7825b 100644 --- a/app/assets/javascripts/diffs/store/getters.js +++ b/app/assets/javascripts/diffs/store/getters.js @@ -9,7 +9,7 @@ export const isParallelView = state => state.diffViewType === PARALLEL_DIFF_VIEW export const isInlineView = state => state.diffViewType === INLINE_DIFF_VIEW_TYPE; export const hasCollapsedFile = state => - state.diffFiles.some(file => file.viewer && file.viewer.collapsed); + state.diffFiles.some(file => file.viewer && file.viewer.automaticallyCollapsed); export const commitId = state => (state.commit && state.commit.id ? state.commit.id : null); @@ -46,15 +46,24 @@ export const diffHasAllCollapsedDiscussions = (state, getters) => diff => { * @param {Object} diff * @returns {Boolean} */ -export const diffHasExpandedDiscussions = (state, getters) => diff => { - const discussions = getters.getDiffFileDiscussions(diff); - - return ( - (discussions && - discussions.length && - discussions.find(discussion => discussion.expanded) !== undefined) || - false - ); +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); }; /** @@ -62,8 +71,25 @@ export const diffHasExpandedDiscussions = (state, getters) => diff => { * @param {Boolean} diff * @returns {Boolean} */ -export const diffHasDiscussions = (state, getters) => diff => - getters.getDiffFileDiscussions(diff).length > 0; +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, + ); +}; /** * Returns an array with the discussions of the given diff diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index 7925c620c4e..13ecf6a997d 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -172,7 +172,7 @@ export default { state.diffFiles.forEach(file => { Object.assign(file, { viewer: Object.assign(file.viewer, { - collapsed: false, + automaticallyCollapsed: false, }), }); }); @@ -355,7 +355,7 @@ export default { const file = state.diffFiles.find(f => f.file_path === filePath); if (file && file.viewer) { - file.viewer.collapsed = collapsed; + file.viewer.automaticallyCollapsed = collapsed; } }, [types.SET_HIDDEN_VIEW_DIFF_FILE_LINES](state, { filePath, lines }) { |