diff options
Diffstat (limited to 'app/assets/javascripts/repository/components')
5 files changed, 217 insertions, 3 deletions
diff --git a/app/assets/javascripts/repository/components/blob_viewers/index.js b/app/assets/javascripts/repository/components/blob_viewers/index.js index 3e6d2e675ed..a480710f8ac 100644 --- a/app/assets/javascripts/repository/components/blob_viewers/index.js +++ b/app/assets/javascripts/repository/components/blob_viewers/index.js @@ -10,6 +10,8 @@ const viewers = { audio: () => import('./audio_viewer.vue'), svg: () => import('./image_viewer.vue'), sketch: () => import('./sketch_viewer.vue'), + notebook: () => import('./notebook_viewer.vue'), + openapi: () => import('./openapi_viewer.vue'), }; export const loadViewer = (type, isUsingLfs) => { diff --git a/app/assets/javascripts/repository/components/blob_viewers/notebook_viewer.vue b/app/assets/javascripts/repository/components/blob_viewers/notebook_viewer.vue new file mode 100644 index 00000000000..1114a0942ec --- /dev/null +++ b/app/assets/javascripts/repository/components/blob_viewers/notebook_viewer.vue @@ -0,0 +1,31 @@ +<script> +import { GlLoadingIcon } from '@gitlab/ui'; +import notebookLoader from '~/blob/notebook'; +import { stripPathTail } from '~/lib/utils/url_utility'; + +export default { + components: { + GlLoadingIcon, + }, + props: { + blob: { + type: Object, + required: true, + }, + }, + data() { + return { + url: this.blob.rawPath, + }; + }, + mounted() { + notebookLoader({ el: this.$refs.viewer, relativeRawPath: stripPathTail(this.url) }); + }, +}; +</script> + +<template> + <div ref="viewer" :data-endpoint="url" data-testid="notebook"> + <gl-loading-icon class="gl-my-4" size="lg" /> + </div> +</template> diff --git a/app/assets/javascripts/repository/components/blob_viewers/openapi_viewer.vue b/app/assets/javascripts/repository/components/blob_viewers/openapi_viewer.vue new file mode 100644 index 00000000000..5665e4b0ec4 --- /dev/null +++ b/app/assets/javascripts/repository/components/blob_viewers/openapi_viewer.vue @@ -0,0 +1,24 @@ +<script> +import renderOpenApi from '~/blob/openapi'; + +export default { + props: { + blob: { + type: Object, + required: true, + }, + }, + data() { + return { + url: this.blob.rawPath, + }; + }, + mounted() { + renderOpenApi(this.$refs.viewer); + }, +}; +</script> + +<template> + <div ref="viewer" class="file-content" :data-endpoint="url" data-testid="openapi"></div> +</template> diff --git a/app/assets/javascripts/repository/components/fork_info.vue b/app/assets/javascripts/repository/components/fork_info.vue new file mode 100644 index 00000000000..980fa140eb5 --- /dev/null +++ b/app/assets/javascripts/repository/components/fork_info.vue @@ -0,0 +1,146 @@ +<script> +import { GlIcon, GlLink, GlSkeletonLoader } from '@gitlab/ui'; +import { s__, sprintf, n__ } from '~/locale'; +import { createAlert } from '~/flash'; +import forkDetailsQuery from '../queries/fork_details.query.graphql'; + +export const i18n = { + forkedFrom: s__('ForkedFromProjectPath|Forked from'), + inaccessibleProject: s__('ForkedFromProjectPath|Forked from an inaccessible project.'), + upToDate: s__('ForksDivergence|Up to date with the upstream repository.'), + unknown: s__('ForksDivergence|This fork has diverged from the upstream repository.'), + behind: s__('ForksDivergence|%{behind} %{commit_word} behind'), + ahead: s__('ForksDivergence|%{ahead} %{commit_word} ahead of'), + behindAndAhead: s__('ForksDivergence|%{messages} the upstream repository.'), + error: s__('ForksDivergence|Failed to fetch fork details. Try again later.'), +}; + +export default { + i18n, + components: { + GlIcon, + GlLink, + GlSkeletonLoader, + }, + apollo: { + project: { + query: forkDetailsQuery, + variables() { + return { + projectPath: this.projectPath, + ref: this.selectedRef, + }; + }, + skip() { + return !this.sourceName; + }, + error(error) { + createAlert({ + message: this.$options.i18n.error, + captureError: true, + error, + }); + }, + }, + }, + props: { + projectPath: { + type: String, + required: true, + }, + selectedRef: { + type: String, + required: true, + }, + sourceName: { + type: String, + required: false, + default: '', + }, + sourcePath: { + type: String, + required: false, + default: '', + }, + }, + data() { + return { + project: { + forkDetails: { + ahead: null, + behind: null, + }, + }, + }; + }, + computed: { + isLoading() { + return this.$apollo.queries.project.loading; + }, + ahead() { + return this.project?.forkDetails?.ahead; + }, + behind() { + return this.project?.forkDetails?.behind; + }, + behindText() { + return sprintf(this.$options.i18n.behind, { + behind: this.behind, + commit_word: n__('commit', 'commits', this.behind), + }); + }, + aheadText() { + return sprintf(this.$options.i18n.ahead, { + ahead: this.ahead, + commit_word: n__('commit', 'commits', this.ahead), + }); + }, + isUnknownDivergence() { + return (!this.ahead && this.ahead !== 0) || (!this.behind && this.behind !== 0); + }, + behindAheadMessage() { + const messages = []; + if (this.behind > 0) { + messages.push(this.behindText); + } + if (this.ahead > 0) { + messages.push(this.aheadText); + } + return messages.join(', '); + }, + hasBehindAheadMessage() { + return this.behindAheadMessage.length > 0; + }, + forkDivergenceMessage() { + if (this.isUnknownDivergence) { + return this.$options.i18n.unknown; + } + if (this.hasBehindAheadMessage) { + return sprintf(this.$options.i18n.behindAndAhead, { + messages: this.behindAheadMessage, + }); + } + return this.$options.i18n.upToDate; + }, + }, +}; +</script> + +<template> + <div class="info-well gl-sm-display-flex gl-flex-direction-column"> + <div class="well-segment gl-p-5 gl-w-full gl-display-flex"> + <gl-icon name="fork" :size="16" class="gl-display-block gl-m-4 gl-text-center" /> + <div v-if="sourceName"> + {{ $options.i18n.forkedFrom }} + <gl-link data-qa-selector="forked_from_link" :href="sourcePath">{{ sourceName }}</gl-link> + <gl-skeleton-loader v-if="isLoading" :lines="1" /> + <div v-else class="gl-text-secondary"> + {{ forkDivergenceMessage }} + </div> + </div> + <div v-else data-testid="inaccessible-project" class="gl-align-items-center gl-display-flex"> + {{ $options.i18n.inaccessibleProject }} + </div> + </div> + </div> +</template> diff --git a/app/assets/javascripts/repository/components/tree_content.vue b/app/assets/javascripts/repository/components/tree_content.vue index 4a8f83458f4..f6d6004ba96 100644 --- a/app/assets/javascripts/repository/components/tree_content.vue +++ b/app/assets/javascripts/repository/components/tree_content.vue @@ -2,12 +2,13 @@ import paginatedTreeQuery from 'shared_queries/repository/paginated_tree.query.graphql'; import { createAlert } from '~/flash'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; -import { __ } from '~/locale'; import { TREE_PAGE_SIZE, TREE_INITIAL_FETCH_COUNT, TREE_PAGE_LIMIT, COMMIT_BATCH_SIZE, + GITALY_UNAVAILABLE_CODE, + i18n, } from '../constants'; import getRefMixin from '../mixins/get_ref'; import projectPathQuery from '../queries/project_path.query.graphql'; @@ -17,6 +18,7 @@ import FilePreview from './preview/index.vue'; import FileTable from './table/index.vue'; export default { + i18n, components: { FileTable, FilePreview, @@ -142,10 +144,19 @@ export default { } }) .catch((error) => { + let gitalyUnavailableError; + if (error.graphQLErrors) { + gitalyUnavailableError = error.graphQLErrors.find( + (e) => e?.extensions?.code === GITALY_UNAVAILABLE_CODE, + ); + } + const message = gitalyUnavailableError + ? this.$options.i18n.gitalyError + : this.$options.i18n.generalError; createAlert({ - message: __('An error occurred while fetching folder content.'), + message, + captureError: true, }); - throw error; }); }, normalizeData(key, data) { |