Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-04-21 02:50:22 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-04-21 02:50:22 +0300
commit9dc93a4519d9d5d7be48ff274127136236a3adb3 (patch)
tree70467ae3692a0e35e5ea56bcb803eb512a10bedb /app/assets/javascripts/repository
parent4b0f34b6d759d6299322b3a54453e930c6121ff0 (diff)
Add latest changes from gitlab-org/gitlab@13-11-stable-eev13.11.0-rc43
Diffstat (limited to 'app/assets/javascripts/repository')
-rw-r--r--app/assets/javascripts/repository/components/blob_content_viewer.vue100
-rw-r--r--app/assets/javascripts/repository/components/breadcrumbs.vue53
-rw-r--r--app/assets/javascripts/repository/components/directory_download_links.vue12
-rw-r--r--app/assets/javascripts/repository/components/table/row.vue22
-rw-r--r--app/assets/javascripts/repository/components/tree_action_link.vue28
-rw-r--r--app/assets/javascripts/repository/components/upload_blob_modal.vue8
-rw-r--r--app/assets/javascripts/repository/index.js42
-rw-r--r--app/assets/javascripts/repository/pages/blob.vue22
-rw-r--r--app/assets/javascripts/repository/queries/blob_info.query.graphql30
-rw-r--r--app/assets/javascripts/repository/router.js20
10 files changed, 286 insertions, 51 deletions
diff --git a/app/assets/javascripts/repository/components/blob_content_viewer.vue b/app/assets/javascripts/repository/components/blob_content_viewer.vue
new file mode 100644
index 00000000000..58b42fb7859
--- /dev/null
+++ b/app/assets/javascripts/repository/components/blob_content_viewer.vue
@@ -0,0 +1,100 @@
+<script>
+import { GlLoadingIcon } from '@gitlab/ui';
+import { uniqueId } from 'lodash';
+import BlobContent from '~/blob/components/blob_content.vue';
+import BlobHeader from '~/blob/components/blob_header.vue';
+import createFlash from '~/flash';
+import { __ } from '~/locale';
+import blobInfoQuery from '../queries/blob_info.query.graphql';
+import projectPathQuery from '../queries/project_path.query.graphql';
+
+export default {
+ components: {
+ BlobHeader,
+ BlobContent,
+ GlLoadingIcon,
+ },
+ apollo: {
+ projectPath: {
+ query: projectPathQuery,
+ },
+ blobInfo: {
+ query: blobInfoQuery,
+ variables() {
+ return {
+ projectPath: this.projectPath,
+ filePath: this.path,
+ };
+ },
+ error() {
+ createFlash({ message: __('An error occurred while loading the file. Please try again.') });
+ },
+ },
+ },
+ provide() {
+ return {
+ blobHash: uniqueId(),
+ };
+ },
+ props: {
+ path: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ projectPath: '',
+ blobInfo: {
+ name: '',
+ size: '',
+ rawBlob: '',
+ type: '',
+ fileType: '',
+ tooLarge: false,
+ path: '',
+ editBlobPath: '',
+ ideEditPath: '',
+ storedExternally: false,
+ rawPath: '',
+ externalStorageUrl: '',
+ replacePath: '',
+ deletePath: '',
+ canLock: false,
+ isLocked: false,
+ lockLink: '',
+ canModifyBlob: true,
+ forkPath: '',
+ simpleViewer: '',
+ richViewer: '',
+ },
+ };
+ },
+ computed: {
+ isLoading() {
+ return this.$apollo.queries.blobInfo.loading;
+ },
+ viewer() {
+ const { fileType, tooLarge, type } = this.blobInfo;
+
+ return { fileType, tooLarge, type };
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-loading-icon v-if="isLoading" />
+ <div v-if="blobInfo && !isLoading">
+ <blob-header :blob="blobInfo" />
+ <blob-content
+ :blob="blobInfo"
+ :content="blobInfo.rawBlob"
+ :is-raw-content="true"
+ :active-viewer="viewer"
+ :loading="false"
+ />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/repository/components/breadcrumbs.vue b/app/assets/javascripts/repository/components/breadcrumbs.vue
index 28d7dec85f4..0b8408643ac 100644
--- a/app/assets/javascripts/repository/components/breadcrumbs.vue
+++ b/app/assets/javascripts/repository/components/breadcrumbs.vue
@@ -5,6 +5,7 @@ import {
GlDropdownSectionHeader,
GlDropdownItem,
GlIcon,
+ GlModalDirective,
} from '@gitlab/ui';
import permissionsQuery from 'shared_queries/repository/permissions.query.graphql';
import { joinPaths, escapeFileUrl } from '~/lib/utils/url_utility';
@@ -12,12 +13,15 @@ import { __ } from '../../locale';
import getRefMixin from '../mixins/get_ref';
import projectPathQuery from '../queries/project_path.query.graphql';
import projectShortPathQuery from '../queries/project_short_path.query.graphql';
+import UploadBlobModal from './upload_blob_modal.vue';
const ROW_TYPES = {
header: 'header',
divider: 'divider',
};
+const UPLOAD_BLOB_MODAL_ID = 'modal-upload-blob';
+
export default {
components: {
GlDropdown,
@@ -25,6 +29,7 @@ export default {
GlDropdownSectionHeader,
GlDropdownItem,
GlIcon,
+ UploadBlobModal,
},
apollo: {
projectShortPath: {
@@ -46,6 +51,9 @@ export default {
},
},
},
+ directives: {
+ GlModal: GlModalDirective,
+ },
mixins: [getRefMixin],
props: {
currentPath: {
@@ -63,6 +71,21 @@ export default {
required: false,
default: false,
},
+ canPushCode: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ selectedBranch: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ originalBranch: {
+ type: String,
+ required: false,
+ default: '',
+ },
newBranchPath: {
type: String,
required: false,
@@ -93,7 +116,13 @@ export default {
required: false,
default: null,
},
+ uploadPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
},
+ uploadBlobModalId: UPLOAD_BLOB_MODAL_ID,
data() {
return {
projectShortPath: '',
@@ -126,7 +155,10 @@ export default {
);
},
canCreateMrFromFork() {
- return this.userPermissions.forkProject && this.userPermissions.createMergeRequestIn;
+ return this.userPermissions?.forkProject && this.userPermissions?.createMergeRequestIn;
+ },
+ showUploadModal() {
+ return this.canEditTree && !this.$apollo.queries.userPermissions.loading;
},
dropdownItems() {
const items = [];
@@ -149,10 +181,9 @@ export default {
{
attrs: {
href: '#modal-upload-blob',
- 'data-target': '#modal-upload-blob',
- 'data-toggle': 'modal',
},
text: __('Upload file'),
+ modalId: UPLOAD_BLOB_MODAL_ID,
},
{
attrs: {
@@ -253,12 +284,26 @@ export default {
<gl-icon name="chevron-down" :size="16" class="float-left" />
</template>
<template v-for="(item, i) in dropdownItems">
- <component :is="getComponent(item.type)" :key="i" v-bind="item.attrs">
+ <component
+ :is="getComponent(item.type)"
+ :key="i"
+ v-bind="item.attrs"
+ v-gl-modal="item.modalId || null"
+ >
{{ item.text }}
</component>
</template>
</gl-dropdown>
</li>
</ol>
+ <upload-blob-modal
+ v-if="showUploadModal"
+ :modal-id="$options.uploadBlobModalId"
+ :commit-message="__('Upload New File')"
+ :target-branch="selectedBranch"
+ :original-branch="originalBranch"
+ :can-push-code="canPushCode"
+ :path="uploadPath"
+ />
</nav>
</template>
diff --git a/app/assets/javascripts/repository/components/directory_download_links.vue b/app/assets/javascripts/repository/components/directory_download_links.vue
index 8c029fc9973..c222a83300d 100644
--- a/app/assets/javascripts/repository/components/directory_download_links.vue
+++ b/app/assets/javascripts/repository/components/directory_download_links.vue
@@ -1,9 +1,9 @@
<script>
-import { GlLink } from '@gitlab/ui';
+import { GlButton } from '@gitlab/ui';
export default {
components: {
- GlLink,
+ GlButton,
},
props: {
currentPath: {
@@ -32,15 +32,15 @@ export default {
<h5 class="m-0 dropdown-bold-header">{{ __('Download this directory') }}</h5>
<div class="dropdown-menu-content">
<div class="btn-group ml-0 w-100">
- <gl-link
+ <gl-button
v-for="(link, index) in normalizedLinks"
:key="index"
:href="link.path"
- :class="{ 'btn-primary': index === 0 }"
- class="btn btn-xs"
+ :variant="index === 0 ? 'confirm' : 'default'"
+ size="small"
>
{{ link.text }}
- </gl-link>
+ </gl-button>
</div>
</div>
</section>
diff --git a/app/assets/javascripts/repository/components/table/row.vue b/app/assets/javascripts/repository/components/table/row.vue
index 70918dd55e4..8ea5fce92fa 100644
--- a/app/assets/javascripts/repository/components/table/row.vue
+++ b/app/assets/javascripts/repository/components/table/row.vue
@@ -12,6 +12,7 @@ import { escapeRegExp } from 'lodash';
import { escapeFileUrl } from '~/lib/utils/url_utility';
import FileIcon from '~/vue_shared/components/file_icon.vue';
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import getRefMixin from '../../mixins/get_ref';
import commitQuery from '../../queries/commit.query.graphql';
@@ -41,7 +42,7 @@ export default {
},
},
},
- mixins: [getRefMixin],
+ mixins: [getRefMixin, glFeatureFlagMixin()],
props: {
id: {
type: String,
@@ -103,10 +104,21 @@ export default {
};
},
computed: {
+ refactorBlobViewerEnabled() {
+ return this.glFeatures.refactorBlobViewer;
+ },
routerLinkTo() {
- return this.isFolder
- ? { path: `/-/tree/${this.escapedRef}/${escapeFileUrl(this.path)}` }
- : null;
+ const blobRouteConfig = { path: `/-/blob/${this.escapedRef}/${escapeFileUrl(this.path)}` };
+ const treeRouteConfig = { path: `/-/tree/${this.escapedRef}/${escapeFileUrl(this.path)}` };
+
+ if (this.refactorBlobViewerEnabled && this.isBlob) {
+ return blobRouteConfig;
+ }
+
+ return this.isFolder ? treeRouteConfig : null;
+ },
+ isBlob() {
+ return this.type === 'blob';
},
isFolder() {
return this.type === 'tree';
@@ -115,7 +127,7 @@ export default {
return this.type === 'commit';
},
linkComponent() {
- return this.isFolder ? 'router-link' : 'a';
+ return this.isFolder || (this.refactorBlobViewerEnabled && this.isBlob) ? 'router-link' : 'a';
},
fullPath() {
return this.path.replace(new RegExp(`^${escapeRegExp(this.currentPath)}/`), '');
diff --git a/app/assets/javascripts/repository/components/tree_action_link.vue b/app/assets/javascripts/repository/components/tree_action_link.vue
deleted file mode 100644
index c5ab150adaf..00000000000
--- a/app/assets/javascripts/repository/components/tree_action_link.vue
+++ /dev/null
@@ -1,28 +0,0 @@
-<script>
-import { GlLink } from '@gitlab/ui';
-
-export default {
- components: {
- GlLink,
- },
- props: {
- path: {
- type: String,
- required: true,
- },
- text: {
- type: String,
- required: true,
- },
- cssClass: {
- type: String,
- required: false,
- default: null,
- },
- },
-};
-</script>
-
-<template>
- <gl-link :href="path" :class="cssClass" class="btn gl-button">{{ text }}</gl-link>
-</template>
diff --git a/app/assets/javascripts/repository/components/upload_blob_modal.vue b/app/assets/javascripts/repository/components/upload_blob_modal.vue
index ec7ba469ca0..d2ff01e7fc1 100644
--- a/app/assets/javascripts/repository/components/upload_blob_modal.vue
+++ b/app/assets/javascripts/repository/components/upload_blob_modal.vue
@@ -168,6 +168,7 @@ export default {
});
},
},
+ validFileMimetypes: [],
};
</script>
<template>
@@ -179,7 +180,12 @@ export default {
:action-cancel="cancelOptions"
@primary.prevent="uploadFile"
>
- <upload-dropzone class="gl-h-200! gl-mb-4" single-file-selection @change="setFile">
+ <upload-dropzone
+ class="gl-h-200! gl-mb-4"
+ single-file-selection
+ :valid-file-mimetypes="$options.validFileMimetypes"
+ @change="setFile"
+ >
<div
v-if="file"
class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
diff --git a/app/assets/javascripts/repository/index.js b/app/assets/javascripts/repository/index.js
index e6969b7c8b2..3a9a2adb417 100644
--- a/app/assets/javascripts/repository/index.js
+++ b/app/assets/javascripts/repository/index.js
@@ -1,14 +1,18 @@
import { GlButton } from '@gitlab/ui';
import Vue from 'vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import { escapeFileUrl } from '~/lib/utils/url_utility';
+import { __ } from '~/locale';
import initWebIdeLink from '~/pages/projects/shared/web_ide_link';
-import { parseBoolean } from '../lib/utils/common_utils';
-import { escapeFileUrl } from '../lib/utils/url_utility';
-import { __ } from '../locale';
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 apolloProvider from './graphql';
+import commitsQuery from './queries/commits.query.graphql';
+import projectPathQuery from './queries/project_path.query.graphql';
+import projectShortPathQuery from './queries/project_short_path.query.graphql';
+import refsQuery from './queries/ref.query.graphql';
import createRouter from './router';
import { updateFormAction } from './utils/dom';
import { setTitle } from './utils/title';
@@ -19,13 +23,32 @@ export default function setupVueRepositoryList() {
const { projectPath, projectShortPath, ref, escapedRef, fullName } = dataset;
const router = createRouter(projectPath, escapedRef);
- apolloProvider.clients.defaultClient.cache.writeData({
+ apolloProvider.clients.defaultClient.cache.writeQuery({
+ query: commitsQuery,
+ data: {
+ commits: [],
+ },
+ });
+
+ apolloProvider.clients.defaultClient.cache.writeQuery({
+ query: projectPathQuery,
data: {
projectPath,
+ },
+ });
+
+ apolloProvider.clients.defaultClient.cache.writeQuery({
+ query: projectShortPathQuery,
+ data: {
projectShortPath,
+ },
+ });
+
+ apolloProvider.clients.defaultClient.cache.writeQuery({
+ query: refsQuery,
+ data: {
ref,
escapedRef,
- commits: [],
},
});
@@ -55,6 +78,8 @@ export default function setupVueRepositoryList() {
const {
canCollaborate,
canEditTree,
+ canPushCode,
+ selectedBranch,
newBranchPath,
newTagPath,
newBlobPath,
@@ -65,8 +90,7 @@ export default function setupVueRepositoryList() {
newDirPath,
} = breadcrumbEl.dataset;
- router.afterEach(({ params: { path = '/' } }) => {
- updateFormAction('.js-upload-blob-form', uploadPath, path);
+ router.afterEach(({ params: { path } }) => {
updateFormAction('.js-create-dir-form', newDirPath, path);
});
@@ -81,12 +105,16 @@ export default function setupVueRepositoryList() {
currentPath: this.$route.params.path,
canCollaborate: parseBoolean(canCollaborate),
canEditTree: parseBoolean(canEditTree),
+ canPushCode: parseBoolean(canPushCode),
+ originalBranch: ref,
+ selectedBranch,
newBranchPath,
newTagPath,
newBlobPath,
forkNewBlobPath,
forkNewDirectoryPath,
forkUploadBlobPath,
+ uploadPath,
},
});
},
diff --git a/app/assets/javascripts/repository/pages/blob.vue b/app/assets/javascripts/repository/pages/blob.vue
new file mode 100644
index 00000000000..27af398be09
--- /dev/null
+++ b/app/assets/javascripts/repository/pages/blob.vue
@@ -0,0 +1,22 @@
+<script>
+// This file is in progress and behind a feature flag, please see the following issue for more:
+// https://gitlab.com/gitlab-org/gitlab/-/issues/323200
+
+import BlobContentViewer from '../components/blob_content_viewer.vue';
+
+export default {
+ components: {
+ BlobContentViewer,
+ },
+ props: {
+ path: {
+ type: String,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <blob-content-viewer :path="path" />
+</template>
diff --git a/app/assets/javascripts/repository/queries/blob_info.query.graphql b/app/assets/javascripts/repository/queries/blob_info.query.graphql
new file mode 100644
index 00000000000..e0bbf12f3eb
--- /dev/null
+++ b/app/assets/javascripts/repository/queries/blob_info.query.graphql
@@ -0,0 +1,30 @@
+query getBlobInfo($projectPath: ID!, $filePath: String!) {
+ project(fullPath: $projectPath) {
+ id
+ repository {
+ blobs(path: $filePath) {
+ name
+ size
+ rawBlob
+ type
+ fileType
+ tooLarge
+ path
+ editBlobPath
+ ideEditPath
+ storedExternally
+ rawPath
+ externalStorageUrl
+ replacePath
+ deletePath
+ canLock
+ isLocked
+ lockLink
+ canModifyBlob
+ forkPath
+ simpleViewer
+ richViewer
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/repository/router.js b/app/assets/javascripts/repository/router.js
index ad6e32d7055..c7f7451fb55 100644
--- a/app/assets/javascripts/repository/router.js
+++ b/app/assets/javascripts/repository/router.js
@@ -2,6 +2,7 @@ import { escapeRegExp } from 'lodash';
import Vue from 'vue';
import VueRouter from 'vue-router';
import { joinPaths } from '../lib/utils/url_utility';
+import BlobPage from './pages/blob.vue';
import IndexPage from './pages/index.vue';
import TreePage from './pages/tree.vue';
@@ -15,6 +16,13 @@ export default function createRouter(base, baseRef) {
}),
};
+ const blobPathRoute = {
+ component: BlobPage,
+ props: (route) => ({
+ path: route.params.path,
+ }),
+ };
+
return new VueRouter({
mode: 'history',
base: joinPaths(gon.relative_url_root || '', base),
@@ -32,6 +40,18 @@ export default function createRouter(base, baseRef) {
...treePathRoute,
},
{
+ name: 'blobPathDecoded',
+ // Sometimes the ref needs decoding depending on how the backend sends it to us
+ path: `(/-)?/blob/${decodeURI(baseRef)}/:path*`,
+ ...blobPathRoute,
+ },
+ {
+ name: 'blobPath',
+ // Support without decoding as well just in case the ref doesn't need to be decoded
+ path: `(/-)?/blob/${escapeRegExp(baseRef)}/:path*`,
+ ...blobPathRoute,
+ },
+ {
path: '/',
name: 'projectRoot',
component: IndexPage,