From 2b45ff9b5040062551214593cecf7c2517625db8 Mon Sep 17 00:00:00 2001 From: Conrad Chan Date: Fri, 7 Jun 2019 10:58:12 -0700 Subject: [PATCH 1/3] New: Show banner when doc has xrefs --- src/i18n/en-US.properties | 2 ++ src/lib/PreviewUI.js | 5 ++-- src/lib/__tests__/metadataAPI-test.js | 5 ++-- src/lib/constants.js | 6 +++++ src/lib/metadataAPI.js | 35 +++++++++++++++--------- src/lib/viewers/doc/DocBaseViewer.js | 38 +++++++++++++++++++++------ 6 files changed, 66 insertions(+), 25 deletions(-) diff --git a/src/i18n/en-US.properties b/src/i18n/en-US.properties index 81eac1016..9317ee1ec 100644 --- a/src/i18n/en-US.properties +++ b/src/i18n/en-US.properties @@ -36,6 +36,8 @@ download_file=Download File text_truncated=This file has been truncated due to size limits. Please download to view the whole file. # Button tooltip to toggle Thumbnails Sidebar toggle_thumbnails=Toggle thumbnails +# Message when file has inaccessible xrefs +hasxrefs=This preview has links you cannot view, open in its native application to view # Error messages # Default preview error message diff --git a/src/lib/PreviewUI.js b/src/lib/PreviewUI.js index 7afd36aab..2dffde24b 100644 --- a/src/lib/PreviewUI.js +++ b/src/lib/PreviewUI.js @@ -320,14 +320,15 @@ class PreviewUI { * @public * @param {string} message - Notification message * @param {string} [buttonText] - Optional text to show in button + * @param {boolean} [persist] - Optional boolean to persist the notification * @return {void} */ - showNotification(message, buttonText) { + showNotification(message, buttonText, persist) { if (!this.notification) { return; } - this.notification.show(message, buttonText); + this.notification.show(message, buttonText, persist); } /** diff --git a/src/lib/__tests__/metadataAPI-test.js b/src/lib/__tests__/metadataAPI-test.js index 4a531d87a..9d036c120 100644 --- a/src/lib/__tests__/metadataAPI-test.js +++ b/src/lib/__tests__/metadataAPI-test.js @@ -36,17 +36,16 @@ describe('metadataAPI', () => { return metadataAPI.getXrefsMetadata('123', 'autocad').then((response) => { expect(stubs.get).to.have.been.called; - expect(response).to.eql(expResponse); + expect(response).to.eql({ hasxrefs: true }); }); }); it('Should return manufactured global template on api 404', () => { - const expResponse = { hasxrefs: 'false' }; stubs.get.rejects({ response: { status: 404 } }); return metadataAPI.getXrefsMetadata('123', 'autocad').then((response) => { expect(stubs.get).to.have.been.called; - expect(response).to.eql(expResponse); + expect(response).to.eql({ hasxrefs: false }); }); }); diff --git a/src/lib/constants.js b/src/lib/constants.js index 449823a74..12a89d7da 100644 --- a/src/lib/constants.js +++ b/src/lib/constants.js @@ -129,3 +129,9 @@ export const ANNOTATOR_EVENT = { error: 'annotationerror', scale: 'scaleannotations' }; + +export const METADATA = { + FIELD_HASXREFS: 'hasxrefs', + SCOPE_GLOBAL: 'global', + TEMPLATE_AUTOCAD: 'autocad' +}; diff --git a/src/lib/metadataAPI.js b/src/lib/metadataAPI.js index e30ee14ee..d2e9f5fa0 100644 --- a/src/lib/metadataAPI.js +++ b/src/lib/metadataAPI.js @@ -1,5 +1,8 @@ import api from './api'; import { getHeaders } from './util'; +import { METADATA } from './constants'; + +const { FIELD_HASXREFS, SCOPE_GLOBAL } = METADATA; const metadataAPI = { /** @@ -14,17 +17,25 @@ const metadataAPI = { return Promise.reject(new Error('id and template are required parameters')); } - return metadataAPI.getMetadata(id, 'global', template, options).catch((err) => { - const { response } = err; - // If the http response is 404, this is a valid case because the metadata template - // may not be initialized on the requested file. Resolve the promise with - // a constructed hasxrefs value - if (response && response.status === 404) { - return Promise.resolve({ hasxrefs: 'false' }); - } - - throw err; - }); + return metadataAPI + .getMetadata(id, SCOPE_GLOBAL, template, options) + .then((response) => { + // The hasxrefs value is returned as a string 'false' or 'true' so we want + // to convert this to a boolean + const { [FIELD_HASXREFS]: hasxrefsValue } = response; + return { ...response, [FIELD_HASXREFS]: hasxrefsValue === 'true' }; + }) + .catch((err) => { + const { response } = err; + // If the http response is 404, this is a valid case because the metadata template + // may not be initialized on the requested file. Resolve the promise with + // a constructed hasxrefs value + if (response && response.status === 404) { + return Promise.resolve({ [FIELD_HASXREFS]: false }); + } + + throw err; + }); }, /** @@ -49,7 +60,7 @@ const metadataAPI = { * @param {string} apiHost - API host * @return {string} The metadata url */ - getMetadataURL(fileId, scope = 'global', template, apiHost) { + getMetadataURL(fileId, scope = SCOPE_GLOBAL, template, apiHost) { return `${apiHost}/2.0/files/${fileId}/metadata/${scope}/${template}`; } }; diff --git a/src/lib/viewers/doc/DocBaseViewer.js b/src/lib/viewers/doc/DocBaseViewer.js index d6caa4b91..6f8897bbb 100644 --- a/src/lib/viewers/doc/DocBaseViewer.js +++ b/src/lib/viewers/doc/DocBaseViewer.js @@ -10,22 +10,23 @@ import RepStatus from '../../RepStatus'; import PreviewError from '../../PreviewError'; import ThumbnailsSidebar from '../../ThumbnailsSidebar'; import { + ANNOTATOR_EVENT, CLASS_BOX_PREVIEW_FIND_BAR, + CLASS_BOX_PREVIEW_THUMBNAILS_CLOSE_ACTIVE, + CLASS_BOX_PREVIEW_THUMBNAILS_CLOSE, + CLASS_BOX_PREVIEW_THUMBNAILS_CONTAINER, + CLASS_BOX_PREVIEW_THUMBNAILS_OPEN_ACTIVE, + CLASS_BOX_PREVIEW_THUMBNAILS_OPEN, CLASS_CRAWLER, CLASS_HIDDEN, CLASS_IS_SCROLLABLE, DOC_STATIC_ASSETS_VERSION, + ENCODING_TYPES, + METADATA, PERMISSION_DOWNLOAD, PRELOAD_REP_NAME, - STATUS_SUCCESS, QUERY_PARAM_ENCODING, - ENCODING_TYPES, - CLASS_BOX_PREVIEW_THUMBNAILS_CONTAINER, - ANNOTATOR_EVENT, - CLASS_BOX_PREVIEW_THUMBNAILS_CLOSE, - CLASS_BOX_PREVIEW_THUMBNAILS_CLOSE_ACTIVE, - CLASS_BOX_PREVIEW_THUMBNAILS_OPEN, - CLASS_BOX_PREVIEW_THUMBNAILS_OPEN_ACTIVE + STATUS_SUCCESS } from '../../constants'; import { checkPermission, getRepresentation } from '../../file'; import { appendQueryParams, createAssetUrlCreator, getMidpoint, getDistance, getClosestPageToPinch } from '../../util'; @@ -40,6 +41,7 @@ import { import { JS, PRELOAD_JS, CSS } from './docAssets'; import { ERROR_CODE, VIEWER_EVENT, LOAD_METRIC, USER_DOCUMENT_THUMBNAIL_EVENTS } from '../../events'; import Timer from '../../Timer'; +import metadataAPI from '../../metadataAPI'; const CURRENT_PAGE_MAP_KEY = 'doc-current-page-map'; const DEFAULT_SCALE_DELTA = 1.1; @@ -69,6 +71,7 @@ const METRICS_WHITELIST = [ USER_DOCUMENT_THUMBNAIL_EVENTS.NAVIGATE, USER_DOCUMENT_THUMBNAIL_EVENTS.OPEN ]; +const { FIELD_HASXREFS, TEMPLATE_AUTOCAD } = METADATA; class DocBaseViewer extends BaseViewer { //-------------------------------------------------------------------------- @@ -326,6 +329,8 @@ class DocBaseViewer extends BaseViewer { super.load(); this.showPreload(); + this.checkForXrefs(); + const template = this.options.representation.content.url_template; this.pdfUrl = this.createContentUrlWithAuthParams(template); @@ -334,6 +339,23 @@ class DocBaseViewer extends BaseViewer { .catch(this.handleAssetError); } + /** + * Checks for xrefs, depending on file extension + * @return {void} + */ + checkForXrefs() { + const { extension, id } = this.options.file; + + if (extension === 'dwg') { + metadataAPI.getXrefsMetadata(id, TEMPLATE_AUTOCAD, this.options).then((response) => { + const { [FIELD_HASXREFS]: hasxrefsValue } = response; + if (hasxrefsValue) { + this.options.ui.showNotification(__('hasxrefs'), null, true); + } + }); + } + } + /** * Loads a document after assets and representation are ready. * From 344e6f091478c3e9c5c254214f0aad8eb787a5ad Mon Sep 17 00:00:00 2001 From: Conrad Chan Date: Fri, 7 Jun 2019 14:05:33 -0700 Subject: [PATCH 2/3] Chore: split out into AutoCADViewer --- src/i18n/en-US.properties | 2 +- src/lib/metadataAPI.js | 4 ++-- src/lib/viewers/doc/AutoCADViewer.js | 32 ++++++++++++++++++++++++++++ src/lib/viewers/doc/DocBaseViewer.js | 22 ------------------- src/lib/viewers/doc/DocLoader.js | 7 ++++++ 5 files changed, 42 insertions(+), 25 deletions(-) create mode 100644 src/lib/viewers/doc/AutoCADViewer.js diff --git a/src/i18n/en-US.properties b/src/i18n/en-US.properties index 9317ee1ec..f4f1ca2c1 100644 --- a/src/i18n/en-US.properties +++ b/src/i18n/en-US.properties @@ -37,7 +37,7 @@ text_truncated=This file has been truncated due to size limits. Please download # Button tooltip to toggle Thumbnails Sidebar toggle_thumbnails=Toggle thumbnails # Message when file has inaccessible xrefs -hasxrefs=This preview has links you cannot view, open in its native application to view +has_x_refs=This preview has links you cannot view, open in its native application to view # Error messages # Default preview error message diff --git a/src/lib/metadataAPI.js b/src/lib/metadataAPI.js index d2e9f5fa0..30b7c4fcb 100644 --- a/src/lib/metadataAPI.js +++ b/src/lib/metadataAPI.js @@ -22,8 +22,8 @@ const metadataAPI = { .then((response) => { // The hasxrefs value is returned as a string 'false' or 'true' so we want // to convert this to a boolean - const { [FIELD_HASXREFS]: hasxrefsValue } = response; - return { ...response, [FIELD_HASXREFS]: hasxrefsValue === 'true' }; + const { [FIELD_HASXREFS]: hasXrefsValue } = response; + return { ...response, [FIELD_HASXREFS]: hasXrefsValue === 'true' }; }) .catch((err) => { const { response } = err; diff --git a/src/lib/viewers/doc/AutoCADViewer.js b/src/lib/viewers/doc/AutoCADViewer.js new file mode 100644 index 000000000..89c26ed7f --- /dev/null +++ b/src/lib/viewers/doc/AutoCADViewer.js @@ -0,0 +1,32 @@ +import DocumentViewer from './DocumentViewer'; +import metadataAPI from '../../metadataAPI'; +import { METADATA } from '../../constants'; + +const { FIELD_HASXREFS, TEMPLATE_AUTOCAD } = METADATA; + +class AutoCADViewer extends DocumentViewer { + /** + * @inheritdoc + */ + load() { + super.load(); + + this.checkForXrefs(); + } + + /** + * Checks for xrefs, depending on file extension + * @return {void} + */ + checkForXrefs() { + const { id } = this.options.file; + + metadataAPI.getXrefsMetadata(id, TEMPLATE_AUTOCAD, this.options).then(({ [FIELD_HASXREFS]: hasxrefsValue }) => { + if (hasxrefsValue) { + this.options.ui.showNotification(__('has_x_refs'), null, true); + } + }); + } +} + +export default AutoCADViewer; diff --git a/src/lib/viewers/doc/DocBaseViewer.js b/src/lib/viewers/doc/DocBaseViewer.js index 6f8897bbb..10af1f9e9 100644 --- a/src/lib/viewers/doc/DocBaseViewer.js +++ b/src/lib/viewers/doc/DocBaseViewer.js @@ -22,7 +22,6 @@ import { CLASS_IS_SCROLLABLE, DOC_STATIC_ASSETS_VERSION, ENCODING_TYPES, - METADATA, PERMISSION_DOWNLOAD, PRELOAD_REP_NAME, QUERY_PARAM_ENCODING, @@ -41,7 +40,6 @@ import { import { JS, PRELOAD_JS, CSS } from './docAssets'; import { ERROR_CODE, VIEWER_EVENT, LOAD_METRIC, USER_DOCUMENT_THUMBNAIL_EVENTS } from '../../events'; import Timer from '../../Timer'; -import metadataAPI from '../../metadataAPI'; const CURRENT_PAGE_MAP_KEY = 'doc-current-page-map'; const DEFAULT_SCALE_DELTA = 1.1; @@ -71,7 +69,6 @@ const METRICS_WHITELIST = [ USER_DOCUMENT_THUMBNAIL_EVENTS.NAVIGATE, USER_DOCUMENT_THUMBNAIL_EVENTS.OPEN ]; -const { FIELD_HASXREFS, TEMPLATE_AUTOCAD } = METADATA; class DocBaseViewer extends BaseViewer { //-------------------------------------------------------------------------- @@ -329,8 +326,6 @@ class DocBaseViewer extends BaseViewer { super.load(); this.showPreload(); - this.checkForXrefs(); - const template = this.options.representation.content.url_template; this.pdfUrl = this.createContentUrlWithAuthParams(template); @@ -339,23 +334,6 @@ class DocBaseViewer extends BaseViewer { .catch(this.handleAssetError); } - /** - * Checks for xrefs, depending on file extension - * @return {void} - */ - checkForXrefs() { - const { extension, id } = this.options.file; - - if (extension === 'dwg') { - metadataAPI.getXrefsMetadata(id, TEMPLATE_AUTOCAD, this.options).then((response) => { - const { [FIELD_HASXREFS]: hasxrefsValue } = response; - if (hasxrefsValue) { - this.options.ui.showNotification(__('hasxrefs'), null, true); - } - }); - } - } - /** * Loads a document after assets and representation are ready. * diff --git a/src/lib/viewers/doc/DocLoader.js b/src/lib/viewers/doc/DocLoader.js index abf8a4a21..089b976d9 100644 --- a/src/lib/viewers/doc/DocLoader.js +++ b/src/lib/viewers/doc/DocLoader.js @@ -6,6 +6,7 @@ import SinglePageViewer from './SinglePageViewer'; import RepStatus from '../../RepStatus'; import { ORIGINAL_REP_NAME, STATUS_SUCCESS } from '../../constants'; import { DOCUMENT_EXTENSIONS } from '../../extensions'; +import AutoCADViewer from './AutoCADViewer'; // Order of the viewers matters. For example, a PDF file can be previewed by using the preferred optimized 'pdf' rep // or the original as a fallback. Additionally, we include multiple entries for the presentation viewer so that it can be @@ -17,6 +18,12 @@ const VIEWERS = [ REP: 'pdf', EXT: ['gslide', 'gslides', 'odp', 'ppt', 'pptx', 'key'] }, + { + NAME: 'AutoCAD', + CONSTRUCTOR: AutoCADViewer, + REP: 'pdf', + EXT: ['dwg'] + }, { NAME: 'Document', CONSTRUCTOR: DocumentViewer, From ca62e86f747576ef7cf9d37752c951eab19d1bb2 Mon Sep 17 00:00:00 2001 From: Conrad Chan Date: Mon, 10 Jun 2019 10:28:06 -0700 Subject: [PATCH 3/3] Chore: add unit tests --- src/lib/__tests__/metadataAPI-test.js | 9 -- src/lib/metadataAPI.js | 25 ++---- .../doc/__tests__/AutoCADViewer-test.js | 82 +++++++++++++++++++ 3 files changed, 88 insertions(+), 28 deletions(-) create mode 100644 src/lib/viewers/doc/__tests__/AutoCADViewer-test.js diff --git a/src/lib/__tests__/metadataAPI-test.js b/src/lib/__tests__/metadataAPI-test.js index 9d036c120..c7141e65b 100644 --- a/src/lib/__tests__/metadataAPI-test.js +++ b/src/lib/__tests__/metadataAPI-test.js @@ -40,15 +40,6 @@ describe('metadataAPI', () => { }); }); - it('Should return manufactured global template on api 404', () => { - stubs.get.rejects({ response: { status: 404 } }); - - return metadataAPI.getXrefsMetadata('123', 'autocad').then((response) => { - expect(stubs.get).to.have.been.called; - expect(response).to.eql({ hasxrefs: false }); - }); - }); - it('Should return an error for any other http 4xx', () => { const expResponse = { response: { status: 400 } }; stubs.get.rejects(expResponse); diff --git a/src/lib/metadataAPI.js b/src/lib/metadataAPI.js index 30b7c4fcb..083fe38ef 100644 --- a/src/lib/metadataAPI.js +++ b/src/lib/metadataAPI.js @@ -17,25 +17,12 @@ const metadataAPI = { return Promise.reject(new Error('id and template are required parameters')); } - return metadataAPI - .getMetadata(id, SCOPE_GLOBAL, template, options) - .then((response) => { - // The hasxrefs value is returned as a string 'false' or 'true' so we want - // to convert this to a boolean - const { [FIELD_HASXREFS]: hasXrefsValue } = response; - return { ...response, [FIELD_HASXREFS]: hasXrefsValue === 'true' }; - }) - .catch((err) => { - const { response } = err; - // If the http response is 404, this is a valid case because the metadata template - // may not be initialized on the requested file. Resolve the promise with - // a constructed hasxrefs value - if (response && response.status === 404) { - return Promise.resolve({ [FIELD_HASXREFS]: false }); - } - - throw err; - }); + return metadataAPI.getMetadata(id, SCOPE_GLOBAL, template, options).then((response) => { + // The hasxrefs value is returned as a string 'false' or 'true' so we want + // to convert this to a boolean + const { [FIELD_HASXREFS]: hasXrefsValue } = response; + return { ...response, [FIELD_HASXREFS]: hasXrefsValue === 'true' }; + }); }, /** diff --git a/src/lib/viewers/doc/__tests__/AutoCADViewer-test.js b/src/lib/viewers/doc/__tests__/AutoCADViewer-test.js new file mode 100644 index 000000000..cdc37c860 --- /dev/null +++ b/src/lib/viewers/doc/__tests__/AutoCADViewer-test.js @@ -0,0 +1,82 @@ +/* eslint-disable no-unused-expressions */ +import DocumentViewer from '../DocumentViewer'; +import AutoCADViewer from '../AutoCADViewer'; +import metadataAPI from '../../../metadataAPI'; +import { METADATA } from '../../../constants'; + +const { FIELD_HASXREFS, TEMPLATE_AUTOCAD } = METADATA; +const sandbox = sinon.sandbox.create(); + +let containerEl; +let autocad; +let stubs = {}; + +describe('lib/viewers/doc/AutoCADViewer', () => { + beforeEach(() => { + containerEl = document.querySelector('.container'); + autocad = new AutoCADViewer({ + container: containerEl, + file: { + id: '0' + } + }); + + stubs.getXrefsMetadata = sandbox.stub(metadataAPI, 'getXrefsMetadata'); + stubs.showNotification = sandbox.stub(); + + autocad.options = { + file: { + id: '123' + }, + ui: { + showNotification: stubs.showNotification + } + }; + }); + + afterEach(() => { + sandbox.verifyAndRestore(); + fixture.cleanup(); + stubs = {}; + }); + + describe('load()', () => { + it('Should call the super.load and checkForXrefs', () => { + stubs.docLoad = sandbox.stub(DocumentViewer.prototype, 'load'); + stubs.checkForXrefs = sandbox.stub(autocad, 'checkForXrefs'); + + autocad.load(); + + expect(stubs.docLoad).to.have.been.called; + expect(stubs.checkForXrefs).to.have.been.called; + }); + }); + + describe('checkForXrefs()', () => { + it('Should show notification if has external refs', () => { + const xrefsPromise = Promise.resolve({ [FIELD_HASXREFS]: true }); + stubs.getXrefsMetadata.resolves(xrefsPromise); + + autocad.checkForXrefs(); + + expect(stubs.getXrefsMetadata).to.have.been.calledWith('123', TEMPLATE_AUTOCAD, autocad.options); + + return xrefsPromise.then(() => { + expect(stubs.showNotification).to.have.been.called; + }); + }); + + it('Should not show notification if does not have external refs', () => { + const xrefsPromise = Promise.resolve({ [FIELD_HASXREFS]: false }); + stubs.getXrefsMetadata.resolves(xrefsPromise); + + autocad.checkForXrefs(); + + expect(stubs.getXrefsMetadata).to.have.been.calledWith('123', TEMPLATE_AUTOCAD, autocad.options); + + return xrefsPromise.then(() => { + expect(stubs.showNotification).not.to.have.been.called; + }); + }); + }); +});