diff --git a/app/assets/javascripts/blob/pdf/pdf_viewer.vue b/app/assets/javascripts/blob/pdf/pdf_viewer.vue index 96d6f5009604d81d58518251dc12cd17857b2080..a1a62abeb6fca330d548f61ccac08c431f798e40 100644 --- a/app/assets/javascripts/blob/pdf/pdf_viewer.vue +++ b/app/assets/javascripts/blob/pdf/pdf_viewer.vue @@ -38,7 +38,13 @@ export default { <div v-if="loading && !error" class="text-center loading"> <gl-loading-icon class="mt-5" size="lg" /> </div> - <pdf-lab v-if="!loadError" :pdf="pdf" @pdflabload="onLoad" @pdflaberror="onError" /> + <pdf-lab + v-if="!loadError" + :pdf="pdf" + @pdflabload="onLoad" + @pdflaberror="onError" + v-on="$listeners" + /> <p v-if="error" class="text-center"> <span v-if="loadError" ref="loadError"> {{ __('An error occurred while loading the file. Please try again later.') }} diff --git a/app/assets/javascripts/pdf/index.vue b/app/assets/javascripts/pdf/index.vue index 6a64538abfea7cb8abff111d12a4f8037a95d283..644eccc023258825a5216d438df21e1b5acaa589 100644 --- a/app/assets/javascripts/pdf/index.vue +++ b/app/assets/javascripts/pdf/index.vue @@ -45,7 +45,7 @@ export default { .promise.then(this.renderPages) .then((pages) => { this.pages = pages; - this.$emit('pdflabload'); + this.$emit('pdflabload', pages.length); }) .catch((error) => { this.$emit('pdflaberror', error); diff --git a/app/assets/javascripts/repository/components/blob_viewers/index.js b/app/assets/javascripts/repository/components/blob_viewers/index.js index b5c4c81b9d87ae53445c05fecae16623b615f43c..62d687e848b16c11e98e0ce6592b09f761081897 100644 --- a/app/assets/javascripts/repository/components/blob_viewers/index.js +++ b/app/assets/javascripts/repository/components/blob_viewers/index.js @@ -40,6 +40,7 @@ export const viewerProps = (type, blob) => { }, pdf: { url: blob.rawPath, + fileSize: blob.rawSize, }, }[type]; }; diff --git a/app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue b/app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue index 3eefcd64b135185e48dd01613bfbd645ff88e70a..ff5d7891660e4853bf048b0d96a133df0b263dcb 100644 --- a/app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue +++ b/app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue @@ -1,16 +1,57 @@ <script> +import { GlButton } from '@gitlab/ui'; import PdfViewer from '~/blob/pdf/pdf_viewer.vue'; +import { __ } from '~/locale'; +import { PDF_MAX_FILE_SIZE, PDF_MAX_PAGE_LIMIT } from '../../constants'; export default { - components: { PdfViewer }, + components: { GlButton, PdfViewer }, + i18n: { + tooLargeDescription: __('This PDF is too large to display, please download to view.'), + tooLargeButtonText: __('Download PDF'), + }, props: { url: { type: String, required: true, }, + fileSize: { + type: Number, + required: true, + }, + }, + data() { + return { totalPages: 0 }; + }, + computed: { + tooLargeToDisplay() { + return this.fileSize > PDF_MAX_FILE_SIZE || this.totalPages > PDF_MAX_PAGE_LIMIT; + }, + }, + methods: { + handleOnLoad(totalPages) { + this.totalPages = totalPages; + }, }, }; </script> <template> - <pdf-viewer :pdf="url" /> + <div> + <pdf-viewer v-if="!tooLargeToDisplay" :pdf="url" @pdflabload="handleOnLoad" /> + + <div v-else class="gl-display-flex gl-flex-direction-column gl-align-items-center gl-p-5"> + <p data-testid="download-help-text">{{ $options.i18n.tooLargeDescription }}</p> + + <gl-button + icon="download" + category="secondary" + variant="confirm" + :href="url" + :aria-label="$options.i18n.tooLargeButtonText" + :title="$options.i18n.tooLargeButtonText" + download + >{{ $options.i18n.tooLargeButtonText }}</gl-button + > + </div> + </div> </template> diff --git a/app/assets/javascripts/repository/constants.js b/app/assets/javascripts/repository/constants.js index b4363c5116536dec1d9dad17ebb66131ef72eec0..cdc4818e4931f4680330ec9d6892a713b5951cc3 100644 --- a/app/assets/javascripts/repository/constants.js +++ b/app/assets/javascripts/repository/constants.js @@ -20,3 +20,6 @@ export const COMMIT_MESSAGE_BODY_MAX_LENGTH = 72; export const LIMITED_CONTAINER_WIDTH_CLASS = 'limit-container-width'; export const I18N_COMMIT_DATA_FETCH_ERROR = __('An error occurred while fetching commit data.'); + +export const PDF_MAX_FILE_SIZE = 10000000; // 10 MB +export const PDF_MAX_PAGE_LIMIT = 50; diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 8ea49e00eac6c5aee6e254ac3c5f8e3718ec4ac2..5b53825626da6f1ef83ded5c683ce59903e960fa 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -12515,6 +12515,9 @@ msgstr "" msgid "Download CSV" msgstr "" +msgid "Download PDF" +msgstr "" + msgid "Download artifacts" msgstr "" @@ -35549,6 +35552,9 @@ msgstr "" msgid "This GitLab instance is undergoing maintenance and is operating in read-only mode." msgstr "" +msgid "This PDF is too large to display, please download to view." +msgstr "" + msgid "This Project is currently archived and read-only. Please unarchive the project first if you want to resume Pull mirroring" msgstr "" diff --git a/spec/frontend/repository/components/blob_viewers/pdf_viewer_spec.js b/spec/frontend/repository/components/blob_viewers/pdf_viewer_spec.js index adee5b9086327c96f0d56c285de009329e1f5105..7d83b66e96d7eee93131aaebf13bbe0b364278b8 100644 --- a/spec/frontend/repository/components/blob_viewers/pdf_viewer_spec.js +++ b/spec/frontend/repository/components/blob_viewers/pdf_viewer_spec.js @@ -1,22 +1,63 @@ import { shallowMount } from '@vue/test-utils'; +import { GlButton } from '@gitlab/ui'; import Component from '~/repository/components/blob_viewers/pdf_viewer.vue'; import PdfViewer from '~/blob/pdf/pdf_viewer.vue'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; describe('PDF Viewer', () => { let wrapper; - const propsData = { url: 'some/pdf_blob.pdf' }; + const defaultPropsData = { url: 'some/pdf_blob.pdf' }; - const createComponent = () => { - wrapper = shallowMount(Component, { propsData }); + const createComponent = (fileSize = 999) => { + wrapper = extendedWrapper( + shallowMount(Component, { propsData: { ...defaultPropsData, fileSize } }), + ); }; const findPDFViewer = () => wrapper.findComponent(PdfViewer); + const findHelpText = () => wrapper.findByTestId('download-help-text'); + const findDownLoadButton = () => wrapper.findComponent(GlButton); it('renders a PDF Viewer component', () => { createComponent(); expect(findPDFViewer().exists()).toBe(true); - expect(findPDFViewer().props('pdf')).toBe(propsData.url); + expect(findPDFViewer().props('pdf')).toBe(defaultPropsData.url); + }); + + describe('Too large', () => { + beforeEach(() => createComponent(20000000)); + + it('does not a PDF Viewer component', () => { + expect(findPDFViewer().exists()).toBe(false); + }); + + it('renders help text', () => { + expect(findHelpText().text()).toBe( + 'This PDF is too large to display, please download to view.', + ); + }); + + it('renders a download button', () => { + expect(findDownLoadButton().exists()).toBe(true); + expect(findDownLoadButton().text()).toBe('Download PDF'); + expect(findDownLoadButton().props('icon')).toBe('download'); + }); + }); + + describe('Too many pages', () => { + beforeEach(() => { + createComponent(); + findPDFViewer().vm.$emit('pdflabload', 100); + }); + + it('does not a PDF Viewer component', () => { + expect(findPDFViewer().exists()).toBe(false); + }); + + it('renders a download button', () => { + expect(findDownLoadButton().exists()).toBe(true); + }); }); });