From 336bbd9de67d5fbb5c6f8f093dbe3551491d2541 Mon Sep 17 00:00:00 2001 From: Jacques Erasmus <jerasmus@gitlab.com> Date: Mon, 29 Mar 2021 09:40:23 +0000 Subject: [PATCH] Add blob content viewer Added blob content viewer to the app --- .../components/blob_content_viewer.vue | 93 +++++++++++++++++++ .../queries/blob_info.query.graphql | 30 ++++++ config/known_invalid_graphql_queries.yml | 1 + locale/gitlab.pot | 3 + .../components/blob_content_viewer_spec.js | 85 +++++++++++++++++ 5 files changed, 212 insertions(+) create mode 100644 app/assets/javascripts/repository/components/blob_content_viewer.vue create mode 100644 app/assets/javascripts/repository/queries/blob_info.query.graphql create mode 100644 spec/frontend/repository/components/blob_content_viewer_spec.js 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 000000000000..a77c1a417878 --- /dev/null +++ b/app/assets/javascripts/repository/components/blob_content_viewer.vue @@ -0,0 +1,93 @@ +<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(), + }; + }, + 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" + :active-viewer="viewer" + :loading="false" + /> + </div> + </div> +</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 000000000000..e0bbf12f3ebc --- /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/config/known_invalid_graphql_queries.yml b/config/known_invalid_graphql_queries.yml index 2989b3a42626..26188d6068f0 100644 --- a/config/known_invalid_graphql_queries.yml +++ b/config/known_invalid_graphql_queries.yml @@ -4,3 +4,4 @@ filenames: - ee/app/assets/javascripts/security_configuration/api_fuzzing/graphql/api_fuzzing_ci_configuration.query.graphql - ee/app/assets/javascripts/security_configuration/api_fuzzing/graphql/create_api_fuzzing_configuration.mutation.graphql - ee/app/assets/javascripts/security_configuration/dast_profiles/graphql/dast_failed_site_validations.query.graphql + - app/assets/javascripts/repository/queries/blob_info.query.graphql diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 6d474eae8916..4db67aa1dc7f 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3533,6 +3533,9 @@ msgstr "" msgid "An error occurred while loading the file. Please try again later." msgstr "" +msgid "An error occurred while loading the file. Please try again." +msgstr "" + msgid "An error occurred while loading the merge request changes." msgstr "" diff --git a/spec/frontend/repository/components/blob_content_viewer_spec.js b/spec/frontend/repository/components/blob_content_viewer_spec.js new file mode 100644 index 000000000000..a0d00ff9a7d3 --- /dev/null +++ b/spec/frontend/repository/components/blob_content_viewer_spec.js @@ -0,0 +1,85 @@ +import { GlLoadingIcon } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import BlobContent from '~/blob/components/blob_content.vue'; +import BlobHeader from '~/blob/components/blob_header.vue'; +import BlobContentViewer from '~/repository/components/blob_content_viewer.vue'; + +let wrapper; +const mockData = { + name: 'some_file.js', + size: 123, + rawBlob: 'raw content', + type: 'text', + fileType: 'text', + tooLarge: false, + path: 'some_file.js', + editBlobPath: 'some_file.js/edit', + ideEditPath: 'some_file.js/ide/edit', + storedExternally: false, + rawPath: 'some_file.js', + externalStorageUrl: 'some_file.js', + replacePath: 'some_file.js/replace', + deletePath: 'some_file.js/delete', + canLock: true, + isLocked: false, + lockLink: 'some_file.js/lock', + canModifyBlob: true, + forkPath: 'some_file.js/fork', + simpleViewer: {}, + richViewer: {}, +}; + +function factory(path, loading = false) { + wrapper = shallowMount(BlobContentViewer, { + propsData: { + path, + }, + mocks: { + $apollo: { + queries: { + blobInfo: { + loading, + }, + }, + }, + }, + }); + + wrapper.setData({ blobInfo: mockData }); +} + +describe('Blob content viewer component', () => { + const findLoadingIcon = () => wrapper.find(GlLoadingIcon); + const findBlobHeader = () => wrapper.find(BlobHeader); + const findBlobContent = () => wrapper.find(BlobContent); + + afterEach(() => { + wrapper.destroy(); + }); + + beforeEach(() => { + factory('some_file.js'); + }); + + it('renders a GlLoadingIcon component', () => { + factory('some_file.js', true); + + expect(findLoadingIcon().exists()).toBe(true); + }); + + it('renders a BlobHeader component', () => { + expect(findBlobHeader().exists()).toBe(true); + }); + + it('renders a BlobContent component', () => { + expect(findBlobContent().exists()).toBe(true); + + expect(findBlobContent().props('loading')).toEqual(false); + expect(findBlobContent().props('content')).toEqual('raw content'); + expect(findBlobContent().props('activeViewer')).toEqual({ + fileType: 'text', + tooLarge: false, + type: 'text', + }); + }); +}); -- GitLab