Commit a743d97b authored by Samantha Ming's avatar Samantha Ming

Use BlobHeader vue component for repo files

Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/323210
parent ad3db46a
......@@ -19,7 +19,7 @@ const apolloProvider = new VueApollo({
const viewBlobEl = document.querySelector('#js-view-blob-app');
if (viewBlobEl) {
const { blobPath, projectPath } = viewBlobEl.dataset;
const { blobPath, projectPath, hasRichViewer } = viewBlobEl.dataset;
// eslint-disable-next-line no-new
new Vue({
......@@ -28,6 +28,7 @@ if (viewBlobEl) {
render(createElement) {
return createElement(BlobContentViewer, {
props: {
hasRichViewer: JSON.parse(hasRichViewer),
path: blobPath,
projectPath,
},
......
......@@ -3,6 +3,7 @@ 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 { SIMPLE_BLOB_VIEWER, RICH_BLOB_VIEWER } from '~/blob/components/constants';
import createFlash from '~/flash';
import { __ } from '~/locale';
import blobInfoQuery from '../queries/blob_info.query.graphql';
......@@ -41,9 +42,15 @@ export default {
type: String,
required: true,
},
hasRichViewer: {
type: Boolean,
required: true,
},
},
data() {
return {
activeViewerType:
this.hasRichViewer && !window.location.hash ? RICH_BLOB_VIEWER : SIMPLE_BLOB_VIEWER,
project: {
repository: {
blobs: {
......@@ -87,10 +94,16 @@ export default {
return nodes[0] || {};
},
viewer() {
const viewer = this.blobInfo.richViewer || this.blobInfo.simpleViewer;
const { fileType, tooLarge, type } = viewer;
return { fileType, tooLarge, type };
const { richViewer, simpleViewer } = this.blobInfo;
return this.activeViewerType === RICH_BLOB_VIEWER ? richViewer : simpleViewer;
},
hasRenderError() {
return Boolean(this.viewer.renderError);
},
},
methods: {
switchViewer(newViewer) {
this.activeViewerType = newViewer || SIMPLE_BLOB_VIEWER;
},
},
};
......@@ -99,8 +112,14 @@ export default {
<template>
<div>
<gl-loading-icon v-if="isLoading" />
<div v-if="blobInfo && !isLoading">
<blob-header :blob="blobInfo" />
<div v-if="blobInfo && !isLoading" class="file-holder">
<blob-header
:blob="blobInfo"
:hide-viewer-switcher="!hasRichViewer"
:active-viewer-type="viewer.type"
:has-render-error="hasRenderError"
@viewer-changed="switchViewer"
/>
<blob-content
:blob="blobInfo"
:content="blobInfo.rawTextBlob"
......
......@@ -6,6 +6,7 @@ query getBlobInfo($projectPath: ID!, $filePath: String!) {
nodes {
webPath
name
size
rawSize
rawTextBlob
fileType
......@@ -18,11 +19,13 @@ query getBlobInfo($projectPath: ID!, $filePath: String!) {
fileType
tooLarge
type
renderError
}
richViewer {
fileType
tooLarge
type
renderError
}
}
}
......
......@@ -37,6 +37,10 @@ class Projects::BlobController < Projects::ApplicationController
feature_category :source_code_management
before_action do
push_frontend_feature_flag(:refactor_blob_viewer, @project, default_enabled: :yaml)
end
def new
commit unless @repository.empty?
end
......
......@@ -12,7 +12,7 @@
- if @code_navigation_path
#js-code-navigation{ data: { code_navigation_path: @code_navigation_path, blob_path: blob.path, definition_path_prefix: project_blob_path(@project, @ref) } }
- if Feature.enabled?(:refactor_blob_viewer, @project, default_enabled: :yaml)
#js-view-blob-app{ data: { blob_path: blob.path, project_path: @project.full_path } }
#js-view-blob-app{ data: { has_rich_viewer: blob.rich_viewer.present?.to_json, blob_path: blob.path, project_path: @project.full_path } }
.gl-spinner-container
= loading_icon(size: 'md')
- else
......
......@@ -5,9 +5,10 @@ import BlobHeader from '~/blob/components/blob_header.vue';
import BlobContentViewer from '~/repository/components/blob_content_viewer.vue';
let wrapper;
const mockData = {
const simpleMockData = {
name: 'some_file.js',
size: 123,
rawSize: 123,
rawTextBlob: 'raw content',
type: 'text',
fileType: 'text',
......@@ -29,15 +30,27 @@ const mockData = {
fileType: 'text',
tooLarge: false,
type: 'simple',
renderError: null,
},
richViewer: null,
};
const richMockData = {
...simpleMockData,
richViewer: {
fileType: 'markup',
tooLarge: false,
type: 'rich',
renderError: null,
},
};
function factory(path, loading = false) {
function factory({ props = {}, mockData = {} } = {}, loading = false) {
wrapper = shallowMount(BlobContentViewer, {
propsData: {
path,
path: 'some_file.js',
projectPath: 'some/path',
hasRichViewer: false,
...props,
},
mocks: {
$apollo: {
......@@ -58,34 +71,82 @@ describe('Blob content viewer component', () => {
const findBlobHeader = () => wrapper.find(BlobHeader);
const findBlobContent = () => wrapper.find(BlobContent);
afterEach(() => {
wrapper.destroy();
beforeEach(() => {
factory({ mockData: simpleMockData });
});
beforeEach(() => {
factory('some_file.js');
afterEach(() => {
wrapper.destroy();
});
it('renders a GlLoadingIcon component', () => {
factory('some_file.js', true);
factory({ mockData: simpleMockData }, true);
expect(findLoadingIcon().exists()).toBe(true);
});
it('renders a BlobHeader component', () => {
expect(findBlobHeader().exists()).toBe(true);
describe('simple viewer', () => {
it('renders a BlobHeader component', () => {
expect(findBlobHeader().props('activeViewerType')).toEqual('simple');
expect(findBlobHeader().props('hasRenderError')).toEqual(false);
expect(findBlobHeader().props('hideViewerSwitcher')).toEqual(true);
expect(findBlobHeader().props('blob')).toEqual(simpleMockData);
});
it('renders a BlobContent component', () => {
expect(findBlobContent().props('loading')).toEqual(false);
expect(findBlobContent().props('content')).toEqual('raw content');
expect(findBlobContent().props('isRawContent')).toBe(true);
expect(findBlobContent().props('activeViewer')).toEqual({
fileType: 'text',
tooLarge: false,
type: 'simple',
renderError: null,
});
});
});
it('renders a BlobContent component', () => {
expect(findBlobContent().exists()).toBe(true);
describe('rich viewer', () => {
beforeEach(() => {
factory({ props: { hasRichViewer: true }, mockData: richMockData });
});
it('renders a BlobHeader component', () => {
expect(findBlobHeader().props('activeViewerType')).toEqual('rich');
expect(findBlobHeader().props('hasRenderError')).toEqual(false);
expect(findBlobHeader().props('hideViewerSwitcher')).toEqual(false);
expect(findBlobHeader().props('blob')).toEqual(richMockData);
});
it('renders a BlobContent component', () => {
expect(findBlobContent().props('loading')).toEqual(false);
expect(findBlobContent().props('content')).toEqual('raw content');
expect(findBlobContent().props('isRawContent')).toBe(true);
expect(findBlobContent().props('activeViewer')).toEqual({
fileType: 'markup',
tooLarge: false,
type: 'rich',
renderError: null,
});
});
it('updates viewer type when viewer changed is clicked', async () => {
expect(findBlobContent().props('activeViewer')).toEqual(
expect.objectContaining({
type: 'rich',
}),
);
expect(findBlobHeader().props('activeViewerType')).toEqual('rich');
findBlobHeader().vm.$emit('viewer-changed', 'simple');
await wrapper.vm.$nextTick();
expect(findBlobContent().props('loading')).toEqual(false);
expect(findBlobContent().props('content')).toEqual('raw content');
expect(findBlobContent().props('isRawContent')).toBe(true);
expect(findBlobContent().props('activeViewer')).toEqual({
fileType: 'text',
tooLarge: false,
type: 'simple',
expect(findBlobHeader().props('activeViewerType')).toEqual('simple');
expect(findBlobContent().props('activeViewer')).toEqual(
expect.objectContaining({
type: 'simple',
}),
);
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment