debian-mirror-gitlab/app/assets/javascripts/diffs/components/diff_file_header.vue

482 lines
14 KiB
Vue
Raw Normal View History

2018-11-08 19:23:39 +05:30
<script>
2020-11-24 15:15:51 +05:30
import {
GlTooltipDirective,
GlSafeHtmlDirective,
GlIcon,
GlButton,
2021-01-03 14:25:43 +05:30
GlButtonGroup,
GlDropdown,
GlDropdownItem,
GlDropdownDivider,
2021-03-11 19:13:27 +05:30
GlFormCheckbox,
2021-01-29 00:20:46 +05:30
GlLoadingIcon,
2020-11-24 15:15:51 +05:30
} from '@gitlab/ui';
2021-03-11 19:13:27 +05:30
import { escape } from 'lodash';
import { mapActions, mapGetters, mapState } from 'vuex';
2021-09-30 23:02:18 +05:30
import { IdState } from 'vendor/vue-virtual-scroller';
2019-07-07 11:18:12 +05:30
import { diffViewerModes } from '~/ide/constants';
2020-01-01 13:55:28 +05:30
import { scrollToElement } from '~/lib/utils/common_utils';
2021-03-11 19:13:27 +05:30
import { truncateSha } from '~/lib/utils/text_utility';
import { __, s__, sprintf } from '~/locale';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import FileIcon from '~/vue_shared/components/file_icon.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { DIFF_FILE_AUTOMATIC_COLLAPSE } from '../constants';
2021-01-03 14:25:43 +05:30
import { DIFF_FILE_HEADER } from '../i18n';
2021-03-11 19:13:27 +05:30
import { collapsedType, isCollapsed } from '../utils/diff_file';
import { reviewable } from '../utils/file_reviews';
import DiffStats from './diff_stats.vue';
2018-11-08 19:23:39 +05:30
export default {
components: {
ClipboardButton,
2020-11-24 15:15:51 +05:30
GlIcon,
2018-11-08 19:23:39 +05:30
FileIcon,
2019-03-02 22:35:43 +05:30
DiffStats,
2020-11-24 15:15:51 +05:30
GlButton,
2021-01-03 14:25:43 +05:30
GlButtonGroup,
GlDropdown,
GlDropdownItem,
GlDropdownDivider,
2021-03-11 19:13:27 +05:30
GlFormCheckbox,
2021-01-29 00:20:46 +05:30
GlLoadingIcon,
2018-11-08 19:23:39 +05:30
},
directives: {
2019-02-15 15:39:39 +05:30
GlTooltip: GlTooltipDirective,
2020-11-24 15:15:51 +05:30
SafeHtml: GlSafeHtmlDirective,
2018-11-08 19:23:39 +05:30
},
2021-09-30 23:02:18 +05:30
mixins: [glFeatureFlagsMixin(), IdState({ idProp: (vm) => vm.diffFile.file_hash })],
2021-01-03 14:25:43 +05:30
i18n: {
...DIFF_FILE_HEADER,
2021-04-29 21:17:54 +05:30
compareButtonLabel: s__('Compare submodule commit revisions'),
2021-01-03 14:25:43 +05:30
},
2018-11-08 19:23:39 +05:30
props: {
2018-12-13 13:39:08 +05:30
discussionPath: {
type: String,
required: false,
default: '',
},
2018-11-08 19:23:39 +05:30
diffFile: {
type: Object,
required: true,
},
collapsible: {
type: Boolean,
required: false,
default: false,
},
addMergeRequestButtons: {
type: Boolean,
required: false,
default: false,
},
expanded: {
type: Boolean,
required: false,
default: true,
},
canCurrentUserFork: {
type: Boolean,
required: true,
},
2020-07-28 23:09:34 +05:30
viewDiffsFileByFile: {
type: Boolean,
required: false,
default: false,
},
2021-03-11 19:13:27 +05:30
showLocalFileReviews: {
type: Boolean,
required: false,
default: false,
},
reviewed: {
type: Boolean,
required: false,
default: false,
},
2021-06-08 01:23:25 +05:30
codequalityDiff: {
type: Array,
2021-04-29 21:17:54 +05:30
required: false,
2021-06-08 01:23:25 +05:30
default: () => [],
2021-04-29 21:17:54 +05:30
},
2018-11-08 19:23:39 +05:30
},
2021-09-30 23:02:18 +05:30
idState() {
2021-01-03 14:25:43 +05:30
return {
moreActionsShown: false,
};
},
2018-11-08 19:23:39 +05:30
computed: {
2021-03-11 19:13:27 +05:30
...mapState('diffs', ['latestDiff']),
2018-11-18 11:00:15 +05:30
...mapGetters('diffs', ['diffHasExpandedDiscussions', 'diffHasDiscussions']),
2019-07-07 11:18:12 +05:30
diffContentIDSelector() {
return `#diff-content-${this.diffFile.file_hash}`;
},
2018-11-08 19:23:39 +05:30
titleLink() {
if (this.diffFile.submodule) {
2019-02-15 15:39:39 +05:30
return this.diffFile.submodule_tree_url || this.diffFile.submodule_link;
2018-11-08 19:23:39 +05:30
}
2019-07-07 11:18:12 +05:30
if (!this.discussionPath) {
return this.diffContentIDSelector;
}
2018-12-13 13:39:08 +05:30
return this.discussionPath;
2018-11-08 19:23:39 +05:30
},
2020-11-24 15:15:51 +05:30
submoduleDiffCompareLinkText() {
if (this.diffFile.submodule_compare) {
const truncatedOldSha = escape(truncateSha(this.diffFile.submodule_compare.old_sha));
const truncatedNewSha = escape(truncateSha(this.diffFile.submodule_compare.new_sha));
return sprintf(
s__('Compare %{oldCommitId}...%{newCommitId}'),
{
oldCommitId: `<span class="commit-sha">${truncatedOldSha}</span>`,
newCommitId: `<span class="commit-sha">${truncatedNewSha}</span>`,
},
false,
);
}
return null;
},
2018-11-08 19:23:39 +05:30
filePath() {
if (this.diffFile.submodule) {
2019-02-15 15:39:39 +05:30
return `${this.diffFile.file_path} @ ${truncateSha(this.diffFile.blob.id)}`;
2018-11-08 19:23:39 +05:30
}
2019-02-15 15:39:39 +05:30
if (this.diffFile.deleted_file) {
return sprintf(__('%{filePath} deleted'), { filePath: this.diffFile.file_path }, false);
2018-11-08 19:23:39 +05:30
}
2019-02-15 15:39:39 +05:30
return this.diffFile.file_path;
2018-11-08 19:23:39 +05:30
},
isUsingLfs() {
2019-02-15 15:39:39 +05:30
return this.diffFile.stored_externally && this.diffFile.external_storage === 'lfs';
2018-11-08 19:23:39 +05:30
},
2021-01-29 00:20:46 +05:30
isCollapsed() {
return isCollapsed(this.diffFile, { fileByFile: this.viewDiffsFileByFile });
},
2018-11-08 19:23:39 +05:30
collapseIcon() {
return this.expanded ? 'chevron-down' : 'chevron-right';
},
viewFileButtonText() {
2020-05-24 23:13:21 +05:30
const truncatedContentSha = escape(truncateSha(this.diffFile.content_sha));
2018-11-08 19:23:39 +05:30
return sprintf(
s__('MergeRequests|View file @ %{commitId}'),
2019-07-07 11:18:12 +05:30
{ commitId: truncatedContentSha },
2018-11-08 19:23:39 +05:30
false,
);
},
viewReplacedFileButtonText() {
2020-05-24 23:13:21 +05:30
const truncatedBaseSha = escape(truncateSha(this.diffFile.diff_refs.base_sha));
2021-01-03 14:25:43 +05:30
return sprintf(s__('MergeRequests|View replaced file @ %{commitId}'), {
commitId: truncatedBaseSha,
});
2018-11-08 19:23:39 +05:30
},
2018-11-18 11:00:15 +05:30
gfmCopyText() {
2019-02-15 15:39:39 +05:30
return `\`${this.diffFile.file_path}\``;
2018-11-18 11:00:15 +05:30
},
2019-07-07 11:18:12 +05:30
isFileRenamed() {
2019-12-04 20:38:33 +05:30
return this.diffFile.renamed_file;
2019-07-07 11:18:12 +05:30
},
isModeChanged() {
return this.diffFile.viewer.name === diffViewerModes.mode_changed;
},
expandDiffToFullFileTitle() {
if (this.diffFile.isShowingFullFile) {
return s__('MRDiff|Show changes only');
}
return s__('MRDiff|Show full file');
},
2021-01-03 14:25:43 +05:30
showEditButton() {
return (
this.diffFile.blob?.readable_text &&
!this.diffFile.deleted_file &&
(this.diffFile.edit_path || this.diffFile.ide_edit_path)
);
},
2021-03-11 19:13:27 +05:30
isReviewable() {
return reviewable(this.diffFile);
},
2021-04-29 21:17:54 +05:30
externalUrlLabel() {
return sprintf(__('View on %{url}'), { url: this.diffFile.formatted_external_url });
},
2021-09-30 23:02:18 +05:30
},
watch: {
'idState.moreActionsShown': {
handler(val) {
const el = this.$el.closest('.vue-recycle-scroller__item-view');
if (this.glFeatures.diffsVirtualScrolling && el) {
// We can't add a style with Vue because of the way the virtual
// scroller library renders the diff files
el.style.zIndex = val ? '1' : null;
}
},
2021-09-04 01:27:46 +05:30
},
2018-11-08 19:23:39 +05:30
},
methods: {
2019-09-30 21:07:59 +05:30
...mapActions('diffs', [
'toggleFileDiscussions',
'toggleFileDiscussionWrappers',
'toggleFullDiff',
2020-11-24 15:15:51 +05:30
'toggleActiveFileByHash',
2021-03-11 19:13:27 +05:30
'reviewFile',
'setFileCollapsedByUser',
2019-09-30 21:07:59 +05:30
]),
2019-12-04 20:38:33 +05:30
handleToggleFile() {
this.$emit('toggleFile');
2018-11-08 19:23:39 +05:30
},
2021-01-03 14:25:43 +05:30
showForkMessage(e) {
if (this.canCurrentUserFork && !this.diffFile.can_modify_blob) {
e.preventDefault();
this.$emit('showForkMessage');
}
2018-11-08 19:23:39 +05:30
},
2019-07-07 11:18:12 +05:30
handleFileNameClick(e) {
const isLinkToOtherPage =
this.diffFile.submodule_tree_url || this.diffFile.submodule_link || this.discussionPath;
if (!isLinkToOtherPage) {
e.preventDefault();
const selector = this.diffContentIDSelector;
scrollToElement(document.querySelector(selector));
window.location.hash = selector;
2020-11-24 15:15:51 +05:30
if (!this.viewDiffsFileByFile) {
this.toggleActiveFileByHash(this.diffFile.file_hash);
}
2019-07-07 11:18:12 +05:30
}
},
2021-01-03 14:25:43 +05:30
setMoreActionsShown(val) {
2021-09-30 23:02:18 +05:30
this.idState.moreActionsShown = val;
2021-01-03 14:25:43 +05:30
},
2021-03-11 19:13:27 +05:30
toggleReview(newReviewedStatus) {
const autoCollapsed =
this.isCollapsed && collapsedType(this.diffFile) === DIFF_FILE_AUTOMATIC_COLLAPSE;
const open = this.expanded;
const closed = !open;
const reviewed = newReviewedStatus;
this.reviewFile({ file: this.diffFile, reviewed });
if (reviewed && autoCollapsed) {
this.setFileCollapsedByUser({
filePath: this.diffFile.file_path,
collapsed: true,
});
}
if ((open && reviewed) || (closed && !reviewed)) {
this.$emit('toggleFile');
}
},
2018-11-08 19:23:39 +05:30
},
};
</script>
<template>
<div
ref="header"
2021-09-30 23:02:18 +05:30
:class="{ 'gl-z-dropdown-menu!': idState.moreActionsShown }"
2018-11-08 19:23:39 +05:30
class="js-file-title file-title file-title-flex-parent"
2021-03-11 19:13:27 +05:30
data-qa-selector="file_title_container"
:data-qa-file-name="filePath"
2019-12-04 20:38:33 +05:30
@click.self="handleToggleFile"
2018-11-08 19:23:39 +05:30
>
2021-01-29 00:20:46 +05:30
<div class="file-header-content">
2020-11-24 15:15:51 +05:30
<gl-icon
2018-11-08 19:23:39 +05:30
v-if="collapsible"
2019-12-04 20:38:33 +05:30
ref="collapseIcon"
2018-11-08 19:23:39 +05:30
:name="collapseIcon"
:size="16"
2020-07-28 23:09:34 +05:30
class="diff-toggle-caret gl-mr-2"
2019-12-04 20:38:33 +05:30
@click.stop="handleToggleFile"
2018-11-08 19:23:39 +05:30
/>
2019-07-07 11:18:12 +05:30
<a
ref="titleWrapper"
2020-07-28 23:09:34 +05:30
:v-once="!viewDiffsFileByFile"
2021-01-29 00:20:46 +05:30
class="gl-mr-2 gl-text-decoration-none! gl-word-break-all"
2019-07-07 11:18:12 +05:30
:href="titleLink"
@click="handleFileNameClick"
>
2021-01-29 00:20:46 +05:30
<file-icon
:file-name="filePath"
2021-09-30 23:02:18 +05:30
:size="16"
2021-01-29 00:20:46 +05:30
aria-hidden="true"
css-classes="gl-mr-2"
:submodule="diffFile.submodule"
/>
2019-07-07 11:18:12 +05:30
<span v-if="isFileRenamed">
2018-11-08 19:23:39 +05:30
<strong
2019-02-15 15:39:39 +05:30
v-gl-tooltip
2021-01-03 14:25:43 +05:30
v-safe-html="diffFile.old_path_html"
2019-02-15 15:39:39 +05:30
:title="diffFile.old_path"
2018-11-08 19:23:39 +05:30
class="file-title-name"
2018-12-05 23:21:45 +05:30
></strong>
2018-11-08 19:23:39 +05:30
<strong
2019-02-15 15:39:39 +05:30
v-gl-tooltip
2021-01-03 14:25:43 +05:30
v-safe-html="diffFile.new_path_html"
2019-02-15 15:39:39 +05:30
:title="diffFile.new_path"
2018-11-08 19:23:39 +05:30
class="file-title-name"
2018-12-05 23:21:45 +05:30
></strong>
2018-11-08 19:23:39 +05:30
</span>
2021-01-03 14:25:43 +05:30
<strong
v-else
v-gl-tooltip
:title="filePath"
class="file-title-name"
data-container="body"
data-qa-selector="file_name_content"
>
2018-11-08 19:23:39 +05:30
{{ filePath }}
</strong>
</a>
<clipboard-button
2019-12-21 20:55:43 +05:30
:title="__('Copy file path')"
2019-02-15 15:39:39 +05:30
:text="diffFile.file_path"
2018-11-18 11:00:15 +05:30
:gfm="gfmCopyText"
2021-01-03 14:25:43 +05:30
data-testid="diff-file-copy-clipboard"
category="tertiary"
2021-11-11 11:23:49 +05:30
data-track-action="click_copy_file_button"
2020-03-13 15:44:24 +05:30
data-track-label="diff_copy_file_path_button"
data-track-property="diff_copy_file"
2018-11-08 19:23:39 +05:30
/>
2019-09-04 21:01:54 +05:30
<small v-if="isModeChanged" ref="fileMode" class="mr-1">
2019-02-15 15:39:39 +05:30
{{ diffFile.a_mode }} {{ diffFile.b_mode }}
2018-11-08 19:23:39 +05:30
</small>
2021-01-29 00:20:46 +05:30
<span v-if="isUsingLfs" class="badge label label-lfs gl-mr-2"> {{ __('LFS') }} </span>
2018-11-08 19:23:39 +05:30
</div>
<div
v-if="!diffFile.submodule && addMergeRequestButtons"
2021-01-29 00:20:46 +05:30
class="file-actions d-flex align-items-center gl-ml-auto gl-align-self-start"
2018-11-08 19:23:39 +05:30
>
2021-09-04 01:27:46 +05:30
<diff-stats
:diff-file="diffFile"
:added-lines="diffFile.added_lines"
:removed-lines="diffFile.removed_lines"
/>
2021-03-11 19:13:27 +05:30
<gl-form-checkbox
v-if="isReviewable && showLocalFileReviews"
v-gl-tooltip.hover
data-testid="fileReviewCheckbox"
2021-04-17 20:07:23 +05:30
class="gl-mr-5 gl-display-flex gl-align-items-center"
2021-03-11 19:13:27 +05:30
:title="$options.i18n.fileReviewTooltip"
:checked="reviewed"
@change="toggleReview"
>
2021-04-17 20:07:23 +05:30
{{ $options.i18n.fileReviewLabel }}
2021-03-11 19:13:27 +05:30
</gl-form-checkbox>
2021-01-03 14:25:43 +05:30
<gl-button-group class="gl-pt-0!">
<gl-button
2019-07-07 11:18:12 +05:30
v-if="diffFile.external_url"
2019-12-04 20:38:33 +05:30
ref="externalLink"
2019-07-07 11:18:12 +05:30
v-gl-tooltip.hover
:href="diffFile.external_url"
2021-04-29 21:17:54 +05:30
:title="externalUrlLabel"
:aria-label="externalUrlLabel"
2019-07-07 11:18:12 +05:30
target="_blank"
2021-11-11 11:23:49 +05:30
data-track-action="click_toggle_external_button"
2020-03-13 15:44:24 +05:30
data-track-label="diff_toggle_external_button"
data-track-property="diff_toggle_external"
2021-01-03 14:25:43 +05:30
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!"
2021-03-11 19:13:27 +05:30
data-qa-selector="dropdown_button"
2021-01-03 14:25:43 +05:30
@show="setMoreActionsShown(true)"
@hidden="setMoreActionsShown(false)"
2019-07-07 11:18:12 +05:30
>
2021-01-03 14:25:43 +05:30
<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"
2021-03-11 19:13:27 +05:30
data-qa-selector="edit_in_ide_button"
2021-01-03 14:25:43 +05:30
>
{{ __('Edit in Web IDE') }}
</gl-dropdown-item>
</template>
2021-01-29 00:20:46 +05:30
<template v-if="!isCollapsed">
2021-01-03 14:25:43 +05:30
<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"
2021-01-29 00:20:46 +05:30
:disabled="diffFile.isLoadingFullFile"
2021-01-03 14:25:43 +05:30
@click="toggleFullDiff(diffFile.file_path)"
>
2021-09-30 23:02:18 +05:30
<gl-loading-icon v-if="diffFile.isLoadingFullFile" size="sm" inline />
2021-01-03 14:25:43 +05:30
{{ expandDiffToFullFileTitle }}
</gl-dropdown-item>
</template>
</gl-dropdown>
</gl-button-group>
2018-11-08 19:23:39 +05:30
</div>
2020-11-24 15:15:51 +05:30
<div
v-if="diffFile.submodule_compare"
class="file-actions d-none d-sm-flex align-items-center flex-wrap"
>
<gl-button
v-gl-tooltip.hover
v-safe-html="submoduleDiffCompareLinkText"
class="submodule-compare"
2021-04-29 21:17:54 +05:30
:title="$options.i18n.compareButtonLabel"
:aria-label="$options.i18n.compareButtonLabel"
2020-11-24 15:15:51 +05:30
:href="diffFile.submodule_compare.url"
/>
</div>
2018-11-08 19:23:39 +05:30
</div>
</template>