431 lines
14 KiB
Vue
431 lines
14 KiB
Vue
<script>
|
|
import { GlButton, GlTooltipDirective } from '@gitlab/ui';
|
|
import { __ } from '~/locale';
|
|
import Shortcuts from '~/behaviors/shortcuts/shortcuts';
|
|
import { shouldDisableShortcuts } from '~/behaviors/shortcuts/shortcuts_toggle';
|
|
import { keysFor, START_SEARCH_PROJECT_FILE } from '~/behaviors/shortcuts/keybindings';
|
|
import { sanitize } from '~/lib/dompurify';
|
|
import { InternalEvents } from '~/tracking';
|
|
import { FIND_FILE_BUTTON_CLICK, REF_SELECTOR_CLICK } from '~/tracking/constants';
|
|
import { visitUrl, joinPaths, webIDEUrl } from '~/lib/utils/url_utility';
|
|
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
|
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
|
import { generateRefDestinationPath } from '~/repository/utils/ref_switcher_utils';
|
|
import RefSelector from '~/ref/components/ref_selector.vue';
|
|
import Breadcrumbs from '~/repository/components/header_area/breadcrumbs.vue';
|
|
import BlobControls from '~/repository/components/header_area/blob_controls.vue';
|
|
import RepositoryOverflowMenu from '~/repository/components/header_area/repository_overflow_menu.vue';
|
|
import CodeDropdown from '~/vue_shared/components/code_dropdown/code_dropdown.vue';
|
|
import SourceCodeDownloadDropdown from '~/vue_shared/components/download_dropdown/download_dropdown.vue';
|
|
import CloneCodeDropdown from '~/vue_shared/components/code_dropdown/clone_code_dropdown.vue';
|
|
import AddToTree from '~/repository/components/header_area/add_to_tree.vue';
|
|
import FileIcon from '~/vue_shared/components/file_icon.vue';
|
|
|
|
export default {
|
|
name: 'HeaderArea',
|
|
i18n: {
|
|
compare: __('Compare'),
|
|
findFile: __('Find file'),
|
|
},
|
|
components: {
|
|
GlButton,
|
|
FileIcon,
|
|
RefSelector,
|
|
Breadcrumbs,
|
|
RepositoryOverflowMenu,
|
|
BlobControls,
|
|
CodeDropdown,
|
|
CompactCodeDropdown: () =>
|
|
import('ee_else_ce/repository/components/code_dropdown/compact_code_dropdown.vue'),
|
|
SourceCodeDownloadDropdown,
|
|
CloneCodeDropdown,
|
|
AddToTree,
|
|
WebIdeLink: () => import('ee_else_ce/vue_shared/components/web_ide_link.vue'),
|
|
LockDirectoryButton: () =>
|
|
import('ee_component/repository/components/lock_directory_button.vue'),
|
|
HeaderLockIcon: () =>
|
|
import('ee_component/repository/components/header_area/header_lock_icon.vue'),
|
|
},
|
|
directives: {
|
|
GlTooltip: GlTooltipDirective,
|
|
},
|
|
mixins: [glFeatureFlagsMixin()],
|
|
inject: [
|
|
'canCollaborate',
|
|
'canEditTree',
|
|
'canPushCode',
|
|
'canPushToBranch',
|
|
'originalBranch',
|
|
'selectedBranch',
|
|
'newBranchPath',
|
|
'newTagPath',
|
|
'newBlobPath',
|
|
'forkNewBlobPath',
|
|
'forkNewDirectoryPath',
|
|
'forkUploadBlobPath',
|
|
'uploadPath',
|
|
'newDirPath',
|
|
'projectRootPath',
|
|
'comparePath',
|
|
'isReadmeView',
|
|
'isFork',
|
|
'needsToFork',
|
|
'isGitpodEnabledForUser',
|
|
'isBlob',
|
|
'showEditButton',
|
|
'showWebIdeButton',
|
|
'isGitpodEnabledForInstance',
|
|
'showPipelineEditorUrl',
|
|
'webIdeUrl',
|
|
'editUrl',
|
|
'pipelineEditorUrl',
|
|
'gitpodUrl',
|
|
'userPreferencesGitpodPath',
|
|
'userProfileEnableGitpodPath',
|
|
'httpUrl',
|
|
'xcodeUrl',
|
|
'sshUrl',
|
|
'kerberosUrl',
|
|
'downloadLinks',
|
|
'downloadArtifacts',
|
|
'isBinary',
|
|
'rootRef',
|
|
],
|
|
provide() {
|
|
return {
|
|
currentRef: this.currentRef,
|
|
};
|
|
},
|
|
props: {
|
|
projectPath: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
refType: {
|
|
type: String,
|
|
required: false,
|
|
default: null,
|
|
},
|
|
currentRef: {
|
|
type: String,
|
|
required: false,
|
|
default: null,
|
|
},
|
|
projectId: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
},
|
|
data() {
|
|
return {
|
|
directoryLocked: false,
|
|
fileLocked: false,
|
|
lockAuthor: undefined,
|
|
};
|
|
},
|
|
computed: {
|
|
isTreeView() {
|
|
return this.$route.name !== 'blobPathDecoded';
|
|
},
|
|
isProjectOverview() {
|
|
return this.$route.name === 'projectRoot';
|
|
},
|
|
isRoot() {
|
|
return !this.currentPath || this.currentPath === '/';
|
|
},
|
|
directoryName() {
|
|
return this.currentPath
|
|
? this.currentPath.split('/').pop()
|
|
: this.projectPath.split('/').pop();
|
|
},
|
|
fileIconName() {
|
|
return this.isTreeView ? 'folder-open' : this.directoryName;
|
|
},
|
|
isLocked() {
|
|
return this.isTreeView ? this.directoryLocked : this.fileLocked;
|
|
},
|
|
getRefType() {
|
|
return this.$route.query.ref_type;
|
|
},
|
|
currentPath() {
|
|
return this.$route.params.path;
|
|
},
|
|
refSelectorQueryParams() {
|
|
return {
|
|
sort: 'updated_desc',
|
|
};
|
|
},
|
|
refSelectorValue() {
|
|
return this.refType ? joinPaths('refs', this.refType, this.currentRef) : this.currentRef;
|
|
},
|
|
webIDEUrl() {
|
|
return this.isBlob
|
|
? this.webIdeUrl
|
|
: webIDEUrl(
|
|
joinPaths(
|
|
'/',
|
|
this.projectPath,
|
|
'edit',
|
|
this.currentRef,
|
|
'-',
|
|
this.$route?.params.path || '',
|
|
'/',
|
|
),
|
|
);
|
|
},
|
|
projectIdAsNumber() {
|
|
return getIdFromGraphQLId(this.projectId);
|
|
},
|
|
findFileTooltip() {
|
|
const { description } = START_SEARCH_PROJECT_FILE;
|
|
const key = this.findFileShortcutKey;
|
|
return shouldDisableShortcuts()
|
|
? null
|
|
: sanitize(`${description} <kbd class="flat gl-ml-1" aria-hidden=true>${key}</kbd>`);
|
|
},
|
|
findFileShortcutKey() {
|
|
return keysFor(START_SEARCH_PROJECT_FILE)[0];
|
|
},
|
|
showCompactCodeDropdown() {
|
|
return this.glFeatures.directoryCodeDropdownUpdates;
|
|
},
|
|
showBlobControls() {
|
|
return this.$route.params.path && this.$route.name === 'blobPathDecoded';
|
|
},
|
|
},
|
|
methods: {
|
|
onInput(selectedRef) {
|
|
InternalEvents.trackEvent(REF_SELECTOR_CLICK);
|
|
visitUrl(generateRefDestinationPath(this.projectRootPath, this.originalBranch, selectedRef));
|
|
},
|
|
handleFindFile() {
|
|
InternalEvents.trackEvent(FIND_FILE_BUTTON_CLICK);
|
|
Shortcuts.focusSearchFile();
|
|
},
|
|
onLockedDirectory({ isLocked, lockAuthor }) {
|
|
this.directoryLocked = isLocked;
|
|
this.lockAuthor = lockAuthor;
|
|
},
|
|
onLockedFile({ isLocked, lockAuthor }) {
|
|
this.fileLocked = isLocked;
|
|
this.lockAuthor = lockAuthor;
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<section :class="{ 'gl-items-center gl-justify-between sm:gl-flex': isProjectOverview }">
|
|
<div class="tree-ref-container mb-2 mb-md-0 gl-flex gl-flex-wrap gl-gap-5">
|
|
<ref-selector
|
|
v-if="!isReadmeView"
|
|
class="tree-ref-holder gl-max-w-26"
|
|
data-testid="ref-dropdown-container"
|
|
:project-id="projectId"
|
|
:value="refSelectorValue"
|
|
use-symbolic-ref-names
|
|
:query-params="refSelectorQueryParams"
|
|
@input="onInput"
|
|
/>
|
|
<breadcrumbs
|
|
v-if="!isReadmeView"
|
|
class="js-repo-breadcrumbs"
|
|
:current-path="currentPath"
|
|
:ref-type="getRefType"
|
|
:can-collaborate="canCollaborate"
|
|
:can-edit-tree="canEditTree"
|
|
:can-push-code="canPushCode"
|
|
:can-push-to-branch="canPushToBranch"
|
|
:original-branch="originalBranch"
|
|
:selected-branch="selectedBranch"
|
|
:new-branch-path="newBranchPath"
|
|
:new-tag-path="newTagPath"
|
|
:new-blob-path="newBlobPath"
|
|
:fork-new-blob-path="forkNewBlobPath"
|
|
:fork-new-directory-path="forkNewDirectoryPath"
|
|
:fork-upload-blob-path="forkUploadBlobPath"
|
|
:upload-path="uploadPath"
|
|
:new-dir-path="newDirPath"
|
|
/>
|
|
</div>
|
|
|
|
<div
|
|
class="gl-flex gl-flex-col gl-items-stretch gl-justify-end sm:gl-flex-row sm:gl-items-center sm:gl-gap-5"
|
|
:class="{ 'gl-my-5': !isProjectOverview }"
|
|
>
|
|
<h1
|
|
v-if="!isReadmeView && !isProjectOverview"
|
|
class="gl-mt-0 gl-inline-flex gl-flex-1 gl-items-center gl-gap-3 gl-break-words gl-text-size-h1 sm:gl-my-0"
|
|
data-testid="repository-heading"
|
|
>
|
|
<file-icon
|
|
:file-name="fileIconName"
|
|
:folder="isTreeView"
|
|
opened
|
|
aria-hidden="true"
|
|
class="gl-inline-flex"
|
|
:class="{ 'gl-text-subtle': isTreeView }"
|
|
/>{{ directoryName }}
|
|
<header-lock-icon
|
|
v-if="!isRoot"
|
|
:is-tree-view="isTreeView"
|
|
:is-locked="isLocked"
|
|
:lock-author="lockAuthor"
|
|
/>
|
|
</h1>
|
|
|
|
<!-- Tree controls -->
|
|
<div
|
|
v-if="!showBlobControls"
|
|
class="tree-controls gl-mb-3 gl-flex gl-flex-wrap gl-gap-3 sm:gl-mb-0"
|
|
data-testid="tree-controls-container"
|
|
>
|
|
<add-to-tree
|
|
v-if="!isReadmeView && showCompactCodeDropdown"
|
|
class="gl-hidden sm:gl-block"
|
|
:current-path="currentPath"
|
|
:can-collaborate="canCollaborate"
|
|
:can-edit-tree="canEditTree"
|
|
:can-push-code="canPushCode"
|
|
:can-push-to-branch="canPushToBranch"
|
|
:original-branch="originalBranch"
|
|
:selected-branch="selectedBranch"
|
|
:new-branch-path="newBranchPath"
|
|
:new-tag-path="newTagPath"
|
|
:new-blob-path="newBlobPath"
|
|
:fork-new-blob-path="forkNewBlobPath"
|
|
:fork-new-directory-path="forkNewDirectoryPath"
|
|
:fork-upload-blob-path="forkUploadBlobPath"
|
|
:upload-path="uploadPath"
|
|
:new-dir-path="newDirPath"
|
|
/>
|
|
<!-- EE: = render_if_exists 'projects/tree/lock_link' -->
|
|
<lock-directory-button
|
|
v-if="!isRoot"
|
|
:project-path="projectPath"
|
|
:path="currentPath"
|
|
@lockedDirectory="onLockedDirectory"
|
|
/>
|
|
<gl-button
|
|
v-gl-tooltip.html="findFileTooltip"
|
|
:aria-keyshortcuts="findFileShortcutKey"
|
|
data-testid="tree-find-file-control"
|
|
class="gl-w-full sm:gl-w-auto"
|
|
@click="handleFindFile"
|
|
>
|
|
{{ $options.i18n.findFile }}
|
|
</gl-button>
|
|
<!-- web ide -->
|
|
<web-ide-link
|
|
class="gl-w-full sm:!gl-ml-0 sm:gl-w-auto"
|
|
data-testid="js-tree-web-ide-link"
|
|
:project-id="projectIdAsNumber"
|
|
:project-path="projectPath"
|
|
:is-fork="isFork"
|
|
:needs-to-fork="needsToFork"
|
|
:is-gitpod-enabled-for-user="isGitpodEnabledForUser"
|
|
:is-blob="isBlob"
|
|
:show-edit-button="showEditButton"
|
|
:show-web-ide-button="showWebIdeButton"
|
|
:is-gitpod-enabled-for-instance="isGitpodEnabledForInstance"
|
|
:show-pipeline-editor-url="showPipelineEditorUrl"
|
|
:web-ide-url="webIDEUrl"
|
|
:edit-url="editUrl"
|
|
:pipeline-editor-url="pipelineEditorUrl"
|
|
:gitpod-url="gitpodUrl"
|
|
:user-preferences-gitpod-path="userPreferencesGitpodPath"
|
|
:user-profile-enable-gitpod-path="userProfileEnableGitpodPath"
|
|
:git-ref="currentRef"
|
|
disable-fork-modal
|
|
v-on="$listeners"
|
|
/>
|
|
<!-- code + mobile panel -->
|
|
<div class="project-code-holder gl-w-full sm:gl-w-auto">
|
|
<div v-if="showCompactCodeDropdown" class="gl-flex gl-justify-end gl-gap-3">
|
|
<add-to-tree
|
|
v-if="!isReadmeView"
|
|
class="sm:gl-hidden"
|
|
:current-path="currentPath"
|
|
:can-collaborate="canCollaborate"
|
|
:can-edit-tree="canEditTree"
|
|
:can-push-code="canPushCode"
|
|
:can-push-to-branch="canPushToBranch"
|
|
:original-branch="originalBranch"
|
|
:selected-branch="selectedBranch"
|
|
:new-branch-path="newBranchPath"
|
|
:new-tag-path="newTagPath"
|
|
:new-blob-path="newBlobPath"
|
|
:fork-new-blob-path="forkNewBlobPath"
|
|
:fork-new-directory-path="forkNewDirectoryPath"
|
|
:fork-upload-blob-path="forkUploadBlobPath"
|
|
:upload-path="uploadPath"
|
|
:new-dir-path="newDirPath"
|
|
/>
|
|
<compact-code-dropdown
|
|
class="gl-ml-auto"
|
|
:ssh-url="sshUrl"
|
|
:http-url="httpUrl"
|
|
:kerberos-url="kerberosUrl"
|
|
:xcode-url="xcodeUrl"
|
|
:web-ide-url="webIDEUrl"
|
|
:gitpod-url="gitpodUrl"
|
|
:current-path="currentPath"
|
|
:directory-download-links="downloadLinks"
|
|
:project-id="projectId"
|
|
:project-path="projectPath"
|
|
:show-web-ide-button="showWebIdeButton"
|
|
:is-gitpod-enabled-for-instance="isGitpodEnabledForInstance"
|
|
:is-gitpod-enabled-for-user="isGitpodEnabledForUser"
|
|
/>
|
|
<repository-overflow-menu
|
|
:full-path="projectPath"
|
|
:path="currentPath"
|
|
:current-ref="currentRef"
|
|
/>
|
|
</div>
|
|
<template v-else-if="!isReadmeView">
|
|
<code-dropdown
|
|
class="git-clone-holder js-git-clone-holder gl-hidden sm:gl-inline-block"
|
|
:ssh-url="sshUrl"
|
|
:http-url="httpUrl"
|
|
:kerberos-url="kerberosUrl"
|
|
:xcode-url="xcodeUrl"
|
|
:current-path="currentPath"
|
|
:directory-download-links="downloadLinks"
|
|
/>
|
|
<div class="gl-flex gl-w-full gl-gap-3 sm:gl-inline-block sm:gl-w-auto">
|
|
<div class="gl-flex gl-w-full gl-items-stretch gl-gap-3 sm:gl-hidden">
|
|
<source-code-download-dropdown
|
|
:download-links="downloadLinks"
|
|
:download-artifacts="downloadArtifacts"
|
|
/>
|
|
<clone-code-dropdown
|
|
class="mobile-git-clone js-git-clone-holder !gl-w-full"
|
|
:ssh-url="sshUrl"
|
|
:http-url="httpUrl"
|
|
:kerberos-url="kerberosUrl"
|
|
/>
|
|
</div>
|
|
<repository-overflow-menu
|
|
:full-path="projectPath"
|
|
:path="currentPath"
|
|
:current-ref="currentRef"
|
|
/>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Blob controls -->
|
|
<blob-controls
|
|
v-if="showBlobControls"
|
|
:project-path="projectPath"
|
|
:project-id-as-number="projectIdAsNumber"
|
|
:ref-type="getRefType"
|
|
:is-binary="isBinary"
|
|
@lockedFile="onLockedFile"
|
|
/>
|
|
</div>
|
|
</section>
|
|
</template>
|