352 lines
11 KiB
Vue
352 lines
11 KiB
Vue
<script>
|
|
/* eslint-disable vue/no-v-html */
|
|
import { escape } from 'lodash';
|
|
import { mapActions, mapGetters } from 'vuex';
|
|
import {
|
|
GlDeprecatedButton,
|
|
GlTooltipDirective,
|
|
GlSafeHtmlDirective,
|
|
GlLoadingIcon,
|
|
GlIcon,
|
|
GlButton,
|
|
} 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';
|
|
|
|
export default {
|
|
components: {
|
|
GlLoadingIcon,
|
|
GlDeprecatedButton,
|
|
ClipboardButton,
|
|
EditButton,
|
|
GlIcon,
|
|
FileIcon,
|
|
DiffStats,
|
|
GlButton,
|
|
},
|
|
directives: {
|
|
GlTooltip: GlTooltipDirective,
|
|
SafeHtml: GlSafeHtmlDirective,
|
|
},
|
|
props: {
|
|
discussionPath: {
|
|
type: String,
|
|
required: false,
|
|
default: '',
|
|
},
|
|
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,
|
|
},
|
|
viewDiffsFileByFile: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
},
|
|
computed: {
|
|
...mapGetters('diffs', ['diffHasExpandedDiscussions', 'diffHasDiscussions']),
|
|
diffContentIDSelector() {
|
|
return `#diff-content-${this.diffFile.file_hash}`;
|
|
},
|
|
|
|
titleLink() {
|
|
if (this.diffFile.submodule) {
|
|
return this.diffFile.submodule_tree_url || this.diffFile.submodule_link;
|
|
}
|
|
|
|
if (!this.discussionPath) {
|
|
return this.diffContentIDSelector;
|
|
}
|
|
|
|
return this.discussionPath;
|
|
},
|
|
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;
|
|
},
|
|
filePath() {
|
|
if (this.diffFile.submodule) {
|
|
return `${this.diffFile.file_path} @ ${truncateSha(this.diffFile.blob.id)}`;
|
|
}
|
|
|
|
if (this.diffFile.deleted_file) {
|
|
return sprintf(__('%{filePath} deleted'), { filePath: this.diffFile.file_path }, false);
|
|
}
|
|
|
|
return this.diffFile.file_path;
|
|
},
|
|
isUsingLfs() {
|
|
return this.diffFile.stored_externally && this.diffFile.external_storage === 'lfs';
|
|
},
|
|
collapseIcon() {
|
|
return this.expanded ? 'chevron-down' : 'chevron-right';
|
|
},
|
|
viewFileButtonText() {
|
|
const truncatedContentSha = escape(truncateSha(this.diffFile.content_sha));
|
|
return sprintf(
|
|
s__('MergeRequests|View file @ %{commitId}'),
|
|
{ commitId: truncatedContentSha },
|
|
false,
|
|
);
|
|
},
|
|
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,
|
|
);
|
|
},
|
|
gfmCopyText() {
|
|
return `\`${this.diffFile.file_path}\``;
|
|
},
|
|
isFileRenamed() {
|
|
return this.diffFile.renamed_file;
|
|
},
|
|
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');
|
|
},
|
|
},
|
|
methods: {
|
|
...mapActions('diffs', [
|
|
'toggleFileDiscussions',
|
|
'toggleFileDiscussionWrappers',
|
|
'toggleFullDiff',
|
|
'toggleActiveFileByHash',
|
|
]),
|
|
handleToggleFile() {
|
|
this.$emit('toggleFile');
|
|
},
|
|
showForkMessage() {
|
|
this.$emit('showForkMessage');
|
|
},
|
|
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;
|
|
if (!this.viewDiffsFileByFile) {
|
|
this.toggleActiveFileByHash(this.diffFile.file_hash);
|
|
}
|
|
}
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
ref="header"
|
|
class="js-file-title file-title file-title-flex-parent"
|
|
@click.self="handleToggleFile"
|
|
>
|
|
<div class="file-header-content">
|
|
<gl-icon
|
|
v-if="collapsible"
|
|
ref="collapseIcon"
|
|
:name="collapseIcon"
|
|
:size="16"
|
|
aria-hidden="true"
|
|
class="diff-toggle-caret gl-mr-2"
|
|
@click.stop="handleToggleFile"
|
|
/>
|
|
<a
|
|
ref="titleWrapper"
|
|
:v-once="!viewDiffsFileByFile"
|
|
class="gl-mr-2"
|
|
:href="titleLink"
|
|
@click="handleFileNameClick"
|
|
>
|
|
<file-icon :file-name="filePath" :size="18" aria-hidden="true" css-classes="gl-mr-2" />
|
|
<span v-if="isFileRenamed">
|
|
<strong
|
|
v-gl-tooltip
|
|
:title="diffFile.old_path"
|
|
class="file-title-name"
|
|
v-html="diffFile.old_path_html"
|
|
></strong>
|
|
→
|
|
<strong
|
|
v-gl-tooltip
|
|
: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">
|
|
{{ filePath }}
|
|
</strong>
|
|
</a>
|
|
|
|
<clipboard-button
|
|
:title="__('Copy file path')"
|
|
:text="diffFile.file_path"
|
|
:gfm="gfmCopyText"
|
|
css-class="btn-default btn-transparent btn-clipboard"
|
|
data-track-event="click_copy_file_button"
|
|
data-track-label="diff_copy_file_path_button"
|
|
data-track-property="diff_copy_file"
|
|
/>
|
|
|
|
<small v-if="isModeChanged" ref="fileMode" class="mr-1">
|
|
{{ diffFile.a_mode }} → {{ diffFile.b_mode }}
|
|
</small>
|
|
|
|
<span v-if="isUsingLfs" class="label label-lfs gl-mr-2"> {{ __('LFS') }} </span>
|
|
</div>
|
|
|
|
<div
|
|
v-if="!diffFile.submodule && addMergeRequestButtons"
|
|
class="file-actions d-none d-sm-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
|
|
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"
|
|
>
|
|
<gl-icon name="external-link" />
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<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"
|
|
:title="s__('Compare submodule commit revisions')"
|
|
:href="diffFile.submodule_compare.url"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|