diff options
Diffstat (limited to 'app/assets/javascripts/repository')
12 files changed, 210 insertions, 21 deletions
diff --git a/app/assets/javascripts/repository/components/blob_button_group.vue b/app/assets/javascripts/repository/components/blob_button_group.vue index 6f540bf8ece..857795c71b0 100644 --- a/app/assets/javascripts/repository/components/blob_button_group.vue +++ b/app/assets/javascripts/repository/components/blob_button_group.vue @@ -1,5 +1,5 @@ <script> -import { GlButtonGroup, GlButton, GlModalDirective } from '@gitlab/ui'; +import { GlButtonGroup, GlButton } from '@gitlab/ui'; import { uniqueId } from 'lodash'; import { sprintf, __ } from '~/locale'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; @@ -20,9 +20,6 @@ export default { DeleteBlobModal, LockButton: () => import('ee_component/repository/components/lock_button.vue'), }, - directives: { - GlModal: GlModalDirective, - }, mixins: [getRefMixin, glFeatureFlagMixin()], inject: { targetBranch: { @@ -73,6 +70,10 @@ export default { type: Boolean, required: true, }, + showForkSuggestion: { + type: Boolean, + required: true, + }, }, computed: { replaceModalId() { @@ -91,6 +92,16 @@ export default { return this.canLock ? 'lock_button' : 'disabled_lock_button'; }, }, + methods: { + showModal(modalId) { + if (this.showForkSuggestion) { + this.$emit('fork'); + return; + } + + this.$refs[modalId].show(); + }, + }, }; </script> @@ -107,14 +118,15 @@ export default { data-testid="lock" :data-qa-selector="lockBtnQASelector" /> - <gl-button v-gl-modal="replaceModalId" data-testid="replace"> + <gl-button data-testid="replace" @click="showModal(replaceModalId)"> {{ $options.i18n.replace }} </gl-button> - <gl-button v-gl-modal="deleteModalId" data-testid="delete"> + <gl-button data-testid="delete" @click="showModal(deleteModalId)"> {{ $options.i18n.delete }} </gl-button> </gl-button-group> <upload-blob-modal + :ref="replaceModalId" :modal-id="replaceModalId" :modal-title="replaceModalTitle" :commit-message="replaceModalTitle" @@ -126,6 +138,7 @@ export default { :primary-btn-text="$options.i18n.replacePrimaryBtnText" /> <delete-blob-modal + :ref="deleteModalId" :modal-id="deleteModalId" :modal-title="deleteModalTitle" :delete-path="deletePath" diff --git a/app/assets/javascripts/repository/components/blob_content_viewer.vue b/app/assets/javascripts/repository/components/blob_content_viewer.vue index f3fa4526999..9368d7e6058 100644 --- a/app/assets/javascripts/repository/components/blob_content_viewer.vue +++ b/app/assets/javascripts/repository/components/blob_content_viewer.vue @@ -105,8 +105,10 @@ export default { forkAndEditPath: '', ideForkAndEditPath: '', storedExternally: false, + externalStorage: '', canModifyBlob: false, canCurrentUserPushToBranch: false, + archived: false, rawPath: '', externalStorageUrl: '', replacePath: '', @@ -166,7 +168,7 @@ export default { return pushCode && downloadCode; }, pathLockedByUser() { - const pathLock = this.project.pathLocks.nodes.find((node) => node.path === this.path); + const pathLock = this.project?.pathLocks?.nodes.find((node) => node.path === this.path); return pathLock ? pathLock.user : null; }, @@ -249,6 +251,7 @@ export default { > <template #actions> <blob-edit + v-if="!blobInfo.archived" :show-edit-button="!isBinaryFileType" :edit-path="blobInfo.editBlobPath" :web-ide-path="blobInfo.ideEditPath" @@ -268,7 +271,7 @@ export default { </gl-button> <blob-button-group - v-if="isLoggedIn" + v-if="isLoggedIn && !blobInfo.archived" :path="path" :name="blobInfo.name" :replace-path="blobInfo.replacePath" @@ -279,6 +282,8 @@ export default { :project-path="projectPath" :is-locked="Boolean(pathLockedByUser)" :can-lock="canLock" + :show-fork-suggestion="showForkSuggestion" + @fork="setForkTarget('ide')" /> </template> </blob-header> @@ -289,6 +294,7 @@ export default { /> <blob-content v-if="!blobViewer" + class="js-syntax-highlight" :rich-viewer="legacyRichViewer" :blob="blobInfo" :content="legacySimpleViewer" diff --git a/app/assets/javascripts/repository/components/blob_controls.vue b/app/assets/javascripts/repository/components/blob_controls.vue new file mode 100644 index 00000000000..3223ed92fe2 --- /dev/null +++ b/app/assets/javascripts/repository/components/blob_controls.vue @@ -0,0 +1,119 @@ +<script> +import { GlButton } from '@gitlab/ui'; +import { __ } from '~/locale'; +import createFlash from '~/flash'; +import getRefMixin from '~/repository/mixins/get_ref'; +import initSourcegraph from '~/sourcegraph'; +import { updateElementsVisibility } from '../utils/dom'; +import blobControlsQuery from '../queries/blob_controls.query.graphql'; + +export default { + i18n: { + findFile: __('Find file'), + blame: __('Blame'), + history: __('History'), + permalink: __('Permalink'), + errorMessage: __('An error occurred while loading the blob controls.'), + }, + buttonClassList: 'gl-sm-w-auto gl-w-full gl-sm-mt-0 gl-mt-3', + components: { + GlButton, + }, + mixins: [getRefMixin], + apollo: { + project: { + query: blobControlsQuery, + variables() { + return { + projectPath: this.projectPath, + filePath: this.filePath, + ref: this.ref, + }; + }, + skip() { + return !this.filePath; + }, + error() { + createFlash({ message: this.$options.i18n.errorMessage }); + }, + }, + }, + props: { + projectPath: { + type: String, + required: true, + }, + }, + data() { + return { + project: { + repository: { + blobs: { + nodes: [ + { + findFilePath: null, + blamePath: null, + historyPath: null, + permalinkPath: null, + storedExternally: null, + externalStorage: null, + }, + ], + }, + }, + }, + }; + }, + computed: { + filePath() { + return this.$route.params.path; + }, + showBlobControls() { + return this.filePath && this.$route.name === 'blobPathDecoded'; + }, + blobInfo() { + return this.project?.repository?.blobs?.nodes[0] || {}; + }, + showBlameButton() { + return !this.blobInfo.storedExternally && this.blobInfo.externalStorage !== 'lfs'; + }, + }, + watch: { + showBlobControls(shouldShow) { + updateElementsVisibility('.tree-controls', !shouldShow); + }, + blobInfo() { + initSourcegraph(); + }, + }, +}; +</script> + +<template> + <div v-if="showBlobControls"> + <gl-button data-testid="find" :href="blobInfo.findFilePath" :class="$options.buttonClassList"> + {{ $options.i18n.findFile }} + </gl-button> + <gl-button + v-if="showBlameButton" + data-testid="blame" + :href="blobInfo.blamePath" + :class="$options.buttonClassList" + > + {{ $options.i18n.blame }} + </gl-button> + + <gl-button data-testid="history" :href="blobInfo.historyPath" :class="$options.buttonClassList"> + {{ $options.i18n.history }} + </gl-button> + + <gl-button + data-testid="permalink" + :href="blobInfo.permalinkPath" + :class="$options.buttonClassList" + class="js-data-file-blob-permalink-url" + > + {{ $options.i18n.permalink }} + </gl-button> + </div> +</template> diff --git a/app/assets/javascripts/repository/components/blob_edit.vue b/app/assets/javascripts/repository/components/blob_edit.vue index fd377ba1b81..69e2bd563c9 100644 --- a/app/assets/javascripts/repository/components/blob_edit.vue +++ b/app/assets/javascripts/repository/components/blob_edit.vue @@ -50,6 +50,7 @@ export default { :web-ide-url="webIdePath" :needs-to-fork="needsToFork" :is-blob="true" + disable-fork-modal @edit="onEdit" /> <div v-else> diff --git a/app/assets/javascripts/repository/components/delete_blob_modal.vue b/app/assets/javascripts/repository/components/delete_blob_modal.vue index 0d3dc06c2c8..f3c9aea36f1 100644 --- a/app/assets/javascripts/repository/components/delete_blob_modal.vue +++ b/app/assets/javascripts/repository/components/delete_blob_modal.vue @@ -146,6 +146,9 @@ export default { /* eslint-enable dot-notation */ }, methods: { + show() { + this.$refs[this.modalId].show(); + }, submitForm(e) { e.preventDefault(); // Prevent modal from closing this.form.showValidation = true; @@ -164,6 +167,7 @@ export default { <template> <gl-modal + :ref="modalId" v-bind="$attrs" data-testid="modal-delete" :modal-id="modalId" diff --git a/app/assets/javascripts/repository/components/fork_suggestion.vue b/app/assets/javascripts/repository/components/fork_suggestion.vue index c266bea319b..471f1dad2e3 100644 --- a/app/assets/javascripts/repository/components/fork_suggestion.vue +++ b/app/assets/javascripts/repository/components/fork_suggestion.vue @@ -32,6 +32,7 @@ export default { class="gl-mr-3" category="secondary" variant="confirm" + data-method="post" :href="forkPath" data-testid="fork" > diff --git a/app/assets/javascripts/repository/components/preview/index.vue b/app/assets/javascripts/repository/components/preview/index.vue index c6e461b10e0..dc5a031c9f3 100644 --- a/app/assets/javascripts/repository/components/preview/index.vue +++ b/app/assets/javascripts/repository/components/preview/index.vue @@ -47,6 +47,9 @@ export default { } }, }, + safeHtmlConfig: { + ADD_TAGS: ['copy-code'], + }, }; </script> @@ -62,7 +65,11 @@ export default { </div> <div class="blob-viewer" data-qa-selector="blob_viewer_content" itemprop="about"> <gl-loading-icon v-if="loading > 0" size="md" color="dark" class="my-4 mx-auto" /> - <div v-else-if="readme" ref="readme" v-safe-html="readme.html"></div> + <div + v-else-if="readme" + ref="readme" + v-safe-html:[$options.safeHtmlConfig]="readme.html" + ></div> </div> </article> </template> diff --git a/app/assets/javascripts/repository/components/upload_blob_modal.vue b/app/assets/javascripts/repository/components/upload_blob_modal.vue index b56c9ce5247..7fcaf772aac 100644 --- a/app/assets/javascripts/repository/components/upload_blob_modal.vue +++ b/app/assets/javascripts/repository/components/upload_blob_modal.vue @@ -136,6 +136,9 @@ export default { }, }, methods: { + show() { + this.$refs[this.modalId].show(); + }, setFile(file) { this.file = file; @@ -206,6 +209,7 @@ export default { <template> <gl-form> <gl-modal + :ref="modalId" :modal-id="modalId" :title="modalTitle" :action-primary="primaryOptions" diff --git a/app/assets/javascripts/repository/index.js b/app/assets/javascripts/repository/index.js index 197b19387cf..120c32caefd 100644 --- a/app/assets/javascripts/repository/index.js +++ b/app/assets/javascripts/repository/index.js @@ -9,6 +9,7 @@ import App from './components/app.vue'; import Breadcrumbs from './components/breadcrumbs.vue'; import DirectoryDownloadLinks from './components/directory_download_links.vue'; import LastCommit from './components/last_commit.vue'; +import BlobControls from './components/blob_controls.vue'; import apolloProvider from './graphql'; import commitsQuery from './queries/commits.query.graphql'; import projectPathQuery from './queries/project_path.query.graphql'; @@ -71,8 +72,26 @@ export default function setupVueRepositoryList() { }, }); + const initBlobControlsApp = () => + new Vue({ + el: document.getElementById('js-blob-controls'), + router, + apolloProvider, + render(h) { + return h(BlobControls, { + props: { + projectPath, + }, + }); + }, + }); + initLastCommitApp(); + if (gon.features.refactorBlobViewer) { + initBlobControlsApp(); + } + router.afterEach(({ params: { path } }) => { setTitle(path, ref, fullName); }); @@ -144,7 +163,7 @@ export default function setupVueRepositoryList() { }`, // Ideally passing this class to `props` should work // But it doesn't work here. :( - class: 'btn btn-default btn-md gl-button ml-sm-0', + class: 'btn btn-default btn-md gl-button', }, }, [__('History')], diff --git a/app/assets/javascripts/repository/queries/blob_controls.query.graphql b/app/assets/javascripts/repository/queries/blob_controls.query.graphql new file mode 100644 index 00000000000..fc1cf5f254b --- /dev/null +++ b/app/assets/javascripts/repository/queries/blob_controls.query.graphql @@ -0,0 +1,18 @@ +query getBlobControls($projectPath: ID!, $filePath: String!, $ref: String!) { + project(fullPath: $projectPath) { + id + repository { + blobs(paths: [$filePath], ref: $ref) { + nodes { + id + findFilePath + blamePath + historyPath + permalinkPath + storedExternally + externalStorage + } + } + } + } +} diff --git a/app/assets/javascripts/repository/queries/blob_info.query.graphql b/app/assets/javascripts/repository/queries/blob_info.query.graphql index 45d1ba80917..ae20a0f0bc4 100644 --- a/app/assets/javascripts/repository/queries/blob_info.query.graphql +++ b/app/assets/javascripts/repository/queries/blob_info.query.graphql @@ -1,22 +1,14 @@ +#import "ee_else_ce/repository/queries/path_locks.fragment.graphql" + query getBlobInfo($projectPath: ID!, $filePath: String!, $ref: String!) { project(fullPath: $projectPath) { - id userPermissions { pushCode downloadCode createMergeRequestIn forkProject } - pathLocks { - nodes { - id - path - user { - id - username - } - } - } + ...ProjectPathLocksFragment repository { empty blobs(paths: [$filePath], ref: $ref) { @@ -35,7 +27,9 @@ query getBlobInfo($projectPath: ID!, $filePath: String!, $ref: String!) { ideForkAndEditPath canModifyBlob canCurrentUserPushToBranch + archived storedExternally + externalStorage rawPath replacePath pipelineEditorPath diff --git a/app/assets/javascripts/repository/queries/path_locks.fragment.graphql b/app/assets/javascripts/repository/queries/path_locks.fragment.graphql new file mode 100644 index 00000000000..868a513362d --- /dev/null +++ b/app/assets/javascripts/repository/queries/path_locks.fragment.graphql @@ -0,0 +1,3 @@ +fragment ProjectPathLocksFragment on Project { + id +} |