Commit 3ba10b63 authored by Douglas Barbosa Alexandre's avatar Douglas Barbosa Alexandre

Merge branch '323210-vue-blob-header' into 'master'

Use BlobHeader vue component for repo files

See merge request gitlab-org/gitlab!60883
parents 2cd392f6 854bcedd
......@@ -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';
......@@ -22,6 +23,11 @@ export default {
filePath: this.path,
};
},
result() {
this.switchViewer(
this.hasRichViewer && !window.location.hash ? RICH_BLOB_VIEWER : SIMPLE_BLOB_VIEWER,
);
},
error() {
createFlash({ message: __('An error occurred while loading the file. Please try again.') });
},
......@@ -44,6 +50,7 @@ export default {
},
data() {
return {
activeViewerType: SIMPLE_BLOB_VIEWER,
project: {
repository: {
blobs: {
......@@ -69,7 +76,7 @@ export default {
canModifyBlob: true,
forkPath: '',
simpleViewer: {},
richViewer: {},
richViewer: null,
},
],
},
......@@ -87,10 +94,19 @@ 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;
},
hasRichViewer() {
return Boolean(this.blobInfo.richViewer);
},
hasRenderError() {
return Boolean(this.viewer.renderError);
},
},
methods: {
switchViewer(newViewer) {
this.activeViewerType = newViewer || SIMPLE_BLOB_VIEWER;
},
},
};
......@@ -99,8 +115,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
}
}
}
......
......@@ -36,6 +36,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
......
......@@ -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,26 @@ 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',
...props,
},
mocks: {
$apollo: {
......@@ -50,7 +62,7 @@ function factory(path, loading = false) {
},
});
wrapper.setData({ blobInfo: mockData });
wrapper.setData(mockData);
}
describe('Blob content viewer component', () => {
......@@ -58,34 +70,84 @@ describe('Blob content viewer component', () => {
const findBlobHeader = () => wrapper.find(BlobHeader);
const findBlobContent = () => wrapper.find(BlobContent);
afterEach(() => {
wrapper.destroy();
beforeEach(() => {
factory({ mockData: { blobInfo: simpleMockData } });
});
beforeEach(() => {
factory('some_file.js');
afterEach(() => {
wrapper.destroy();
});
it('renders a GlLoadingIcon component', () => {
factory('some_file.js', true);
factory({ mockData: { blobInfo: 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({
mockData: { blobInfo: richMockData, activeViewerType: 'rich' },
});
});
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',
}),
);
});
});
});
......@@ -11,7 +11,9 @@ describe('Repository blob page component', () => {
const path = 'file.js';
beforeEach(() => {
wrapper = shallowMount(BlobPage, { propsData: { path, projectPath: 'some/path' } });
wrapper = shallowMount(BlobPage, {
propsData: { path, projectPath: 'some/path' },
});
});
afterEach(() => {
......
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