Commit dfc21444 authored by Jacques Erasmus's avatar Jacques Erasmus

Merge branch '324320-blob-download-viewer' into 'master'

Create download blob viewer

See merge request gitlab-org/gitlab!65915
parents 604fe9aa aee4baf8
<script>
import { GlIcon, GlLink } from '@gitlab/ui';
import { numberToHumanSize } from '~/lib/utils/number_utils';
import { sprintf, __ } from '~/locale';
export default {
components: {
GlIcon,
GlLink,
},
props: {
fileName: {
type: String,
required: true,
},
filePath: {
type: String,
required: true,
},
fileSize: {
type: Number,
required: false,
default: 0,
},
},
computed: {
downloadFileSize() {
return numberToHumanSize(this.fileSize);
},
downloadText() {
if (this.fileSize > 0) {
return sprintf(__('Download (%{fileSizeReadable})'), {
fileSizeReadable: this.downloadFileSize,
});
}
return __('Download');
},
},
};
</script>
<template>
<div class="gl-text-center gl-py-13 gl-bg-gray-50">
<gl-link :href="filePath" rel="nofollow" :download="fileName" target="_blank">
<div>
<gl-icon :size="16" name="download" class="gl-text-gray-900" />
</div>
<h4>{{ downloadText }}</h4>
</gl-link>
</div>
</template>
......@@ -5,8 +5,7 @@ export const loadViewer = (type) => {
case 'text':
return () => import(/* webpackChunkName: 'blob_text_viewer' */ './text_viewer.vue');
case 'download':
// TODO (follow-up): import the download viewer
return null; // () => import(/* webpackChunkName: 'blob_download_viewer' */ './download_viewer.vue');
return () => import(/* webpackChunkName: 'blob_download_viewer' */ './download_viewer.vue');
default:
return null;
}
......@@ -19,5 +18,10 @@ export const viewerProps = (type, blob) => {
fileName: blob.name,
readOnly: true,
},
download: {
fileName: blob.name,
filePath: blob.rawPath,
fileSize: blob.rawSize,
},
}[type];
};
......@@ -87,6 +87,12 @@
padding-bottom: $gl-spacing-scale-8;
}
// Will be moved to @gitlab/ui in https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1495
.gl-py-13 {
padding-top: $gl-spacing-scale-13;
padding-bottom: $gl-spacing-scale-13;
}
.gl-transition-property-stroke-opacity {
transition-property: stroke-opacity;
}
......
......@@ -11683,6 +11683,9 @@ msgstr ""
msgid "Download %{name} artifact"
msgstr ""
msgid "Download (%{fileSizeReadable})"
msgstr ""
msgid "Download (%{size})"
msgstr ""
......
......@@ -12,6 +12,7 @@ import BlobButtonGroup from '~/repository/components/blob_button_group.vue';
import BlobContentViewer from '~/repository/components/blob_content_viewer.vue';
import BlobEdit from '~/repository/components/blob_edit.vue';
import { loadViewer, viewerProps } from '~/repository/components/blob_viewers';
import DownloadViewer from '~/repository/components/blob_viewers/download_viewer.vue';
import TextViewer from '~/repository/components/blob_viewers/text_viewer.vue';
import blobInfoQuery from '~/repository/queries/blob_info.query.graphql';
......@@ -124,6 +125,7 @@ describe('Blob content viewer component', () => {
const findBlobContent = () => wrapper.findComponent(BlobContent);
const findBlobButtonGroup = () => wrapper.findComponent(BlobButtonGroup);
const findTextViewer = () => wrapper.findComponent(TextViewer);
const findDownloadViewer = () => wrapper.findComponent(DownloadViewer);
afterEach(() => {
wrapper.destroy();
......@@ -225,6 +227,7 @@ describe('Blob content viewer component', () => {
describe('Blob viewer', () => {
beforeEach(() => {
loadViewer.mockClear();
viewerProps.mockClear();
});
it('does not render a BlobContent component if a Blob viewer is available', () => {
......@@ -242,6 +245,31 @@ describe('Blob content viewer component', () => {
expect(findTextViewer().exists()).toBe(true);
});
it('renders a DownloadViewer for download files', async () => {
loadViewer.mockReturnValue(DownloadViewer);
viewerProps.mockReturnValue({
filePath: '/some/file/path',
fileName: 'test.js',
fileSize: 100,
});
const downloadSimpleMockData = {
...simpleMockData,
fileType: null,
simpleViewer: {
...simpleMockData.simpleViewer,
fileType: 'download',
},
};
factory({ mockData: { blobInfo: downloadSimpleMockData } });
await nextTick();
expect(loadViewer).toHaveBeenCalledWith('download');
expect(findDownloadViewer().exists()).toBe(true);
});
});
describe('BlobHeader action slot', () => {
......
import { GlLink, GlIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { numberToHumanSize } from '~/lib/utils/number_utils';
import DownloadViewer from '~/repository/components/blob_viewers/download_viewer.vue';
describe('Text Viewer', () => {
let wrapper;
const DEFAULT_PROPS = {
fileName: 'file_name.js',
filePath: '/some/file/path',
fileSize: 2269674,
};
const createComponent = (props = {}) => {
wrapper = shallowMount(DownloadViewer, {
propsData: {
...DEFAULT_PROPS,
...props,
},
});
};
it('renders component', () => {
createComponent();
const { fileName, filePath, fileSize } = DEFAULT_PROPS;
expect(wrapper.props()).toMatchObject({
fileName,
filePath,
fileSize,
});
});
it('renders download human readable file size text', () => {
createComponent();
const downloadText = `Download (${numberToHumanSize(DEFAULT_PROPS.fileSize)})`;
expect(wrapper.text()).toBe(downloadText);
});
it('renders download text', () => {
createComponent({
fileSize: 0,
});
expect(wrapper.text()).toBe('Download');
});
it('renders download link', () => {
createComponent();
const { filePath, fileName } = DEFAULT_PROPS;
expect(wrapper.findComponent(GlLink).attributes()).toMatchObject({
rel: 'nofollow',
target: '_blank',
href: filePath,
download: fileName,
});
});
it('renders download icon', () => {
createComponent();
expect(wrapper.findComponent(GlIcon).props()).toMatchObject({
name: 'download',
size: 16,
});
});
});
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