-
Notifications
You must be signed in to change notification settings - Fork 351
feat(preview): support loading the Preview library from npm #4695
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
041e395
07ba1a3
a188c00
1b94191
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -138,6 +138,8 @@ type Props = { | |
| isLarge: boolean, | ||
| isVeryLarge?: boolean, | ||
| language: string, | ||
| // Required when useNpmBoxContentPreview is on. Import loadBoxContentPreview from its own file and pass it here. | ||
| loadPreviewModule?: () => Promise<{ Preview?: any }>, | ||
| loadingIndicatorDelayMs?: number, | ||
| logoUrl?: string, | ||
| measureRef: Function, | ||
|
|
@@ -157,6 +159,9 @@ type Props = { | |
| }, | ||
| previewLibraryVersion: string, | ||
| previewMode?: 'default' | 'shared_file' | 'shared_folder' | 'editable_shared_file' | 'inline_feed', | ||
| // npm path only: URL of the pdfjs worker file, resolved by the consumer's bundler. | ||
| // Passed to box-content-preview in the show() options as `pdfjs.workerSrc`. | ||
| pdfjsWorkerSrc?: string, | ||
| resin?: { | ||
| recordAction?: (data: Object) => void, | ||
| }, | ||
|
|
@@ -281,6 +286,10 @@ class ContentPreview extends React.PureComponent<Props, State> { | |
|
|
||
| preview: any; | ||
|
|
||
| npmPreviewModule: ?{ Preview: any }; | ||
|
|
||
| npmPreviewLoadFailed: boolean = false; | ||
|
|
||
| api: API; | ||
|
|
||
| // Defines a generic type for ContentSidebar, since an import would interfere with code splitting | ||
|
|
@@ -472,10 +481,14 @@ class ContentPreview extends React.PureComponent<Props, State> { | |
| * @return {void} | ||
| */ | ||
| componentDidMount(): void { | ||
| // Always load Box.Preview library assets | ||
| // Always load preview library assets (npm module or CDN script) | ||
|
jackiejou marked this conversation as resolved.
|
||
| // Even when children are provided, we need assets ready for transitions | ||
| this.loadStylesheet(); | ||
| this.loadScript(); | ||
| if (this.shouldUseNpmPreview()) { | ||
| this.loadNpmPreview(); | ||
| } else { | ||
| this.loadStylesheet(); | ||
| this.loadScript(); | ||
|
Comment on lines
+486
to
+490
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [question] Eventually shouldUseNpmPreview feature related code will be cleaned up I assume? In that case, will other consumer that has been leveraging the CDN script also be forced to switch to using npm installed version only?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, the CDN will stay for legacy users. |
||
| } | ||
|
|
||
| const { currentFileId } = this.state; | ||
| const { loadingIndicatorDelayMs } = this.props; | ||
|
|
@@ -492,6 +505,64 @@ class ContentPreview extends React.PureComponent<Props, State> { | |
| this.focusPreview(); | ||
| } | ||
|
|
||
| shouldUseNpmPreview(): boolean { | ||
| return isFeatureEnabled(this.props.features, 'useNpmBoxContentPreview'); | ||
| } | ||
|
|
||
| loadNpmPreview = async (): Promise<void> => { | ||
| if (this.npmPreviewModule) { | ||
| return; | ||
| } | ||
|
|
||
| const { loadPreviewModule } = this.props; | ||
| if (!loadPreviewModule) { | ||
| this.onNpmPreviewLoadError('loadPreviewModule is required when useNpmBoxContentPreview is enabled'); | ||
| return; | ||
| } | ||
|
|
||
| let previewModule; | ||
| try { | ||
| previewModule = await loadPreviewModule(); | ||
| } catch (error) { | ||
| this.onNpmPreviewLoadError( | ||
| `Failed to load the box-content-preview module: ${error?.message || String(error)}`, | ||
| ); | ||
| return; | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| if (!previewModule.Preview) { | ||
| this.onNpmPreviewLoadError('box-content-preview module has no Preview export'); | ||
| return; | ||
| } | ||
|
|
||
| this.npmPreviewModule = previewModule; | ||
| this.loadPreview(); | ||
| }; | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| getNpmPreviewLocation(): { baseURI: string, locale: string, staticBaseURI: string, version: string } { | ||
| const { language, previewLibraryVersion, staticHost, staticPath } = this.props; | ||
| const trailingSlash = staticHost.endsWith('/') ? '' : '/'; | ||
| const staticBaseURI = `${staticHost}${trailingSlash}${staticPath}/`; | ||
| return { | ||
| baseURI: `${staticBaseURI}${previewLibraryVersion}/${language}/`, | ||
| locale: language, | ||
| staticBaseURI, | ||
| version: previewLibraryVersion, | ||
| }; | ||
| } | ||
|
|
||
| onNpmPreviewLoadError(message: string): void { | ||
| const { onError } = this.props; | ||
| const error = { | ||
| code: ERROR_CODE_UNKNOWN, | ||
| message, | ||
| }; | ||
| this.npmPreviewLoadFailed = true; | ||
| this.endLoadingSession(); | ||
| this.setState({ error }); | ||
| onError(error, ERROR_CODE_UNKNOWN, { error }, ORIGIN_PREVIEW); | ||
| } | ||
|
|
||
| static getDerivedStateFromProps(props: Props, state: State) { | ||
| const { fileId } = props; | ||
|
|
||
|
|
@@ -628,6 +699,9 @@ class ContentPreview extends React.PureComponent<Props, State> { | |
| * @return {boolean} true if preview is loaded | ||
| */ | ||
| isPreviewLibraryLoaded(): boolean { | ||
| if (this.shouldUseNpmPreview()) { | ||
| return !!this.npmPreviewModule; | ||
| } | ||
| return !!global.Box && !!global.Box.Preview; | ||
| } | ||
|
|
||
|
|
@@ -1013,8 +1087,14 @@ class ContentPreview extends React.PureComponent<Props, State> { | |
| showProgress: false, | ||
| skipServerUpdate: true, | ||
| useHotkeys: false, | ||
| ...(this.npmPreviewModule && this.props.pdfjsWorkerSrc | ||
| ? { pdfjs: { workerSrc: this.props.pdfjsWorkerSrc } } | ||
| : {}), | ||
| ...(this.npmPreviewModule ? { location: this.getNpmPreviewLocation() } : {}), | ||
| }; | ||
| const { Preview } = global.Box; | ||
|
|
||
| const Preview = | ||
| this.shouldUseNpmPreview() && this.npmPreviewModule ? this.npmPreviewModule.Preview : global.Box.Preview; | ||
| this.preview = new Preview(); | ||
| this.preview.addListener('load', this.onPreviewLoad); | ||
| this.preview.addListener('preload', this.endLoadingSession); | ||
|
|
@@ -1032,7 +1112,7 @@ class ContentPreview extends React.PureComponent<Props, State> { | |
| this.preview.show(file.id, token, { | ||
| ...previewOptions, | ||
| ...omit(rest, Object.keys(previewOptions)), | ||
| annotatorToken: tokenOrTokenFunction, | ||
| annotatorToken: typeof tokenOrTokenFunction === 'function' ? tokenOrTokenFunction : undefined, | ||
| }); | ||
| if (advancedContentInsights) { | ||
| this.preview.addListener('advanced_insights_report', onContentInsightsEventReport); | ||
|
|
@@ -1081,6 +1161,11 @@ class ContentPreview extends React.PureComponent<Props, State> { | |
| fetchFileSuccessCallback = (file: BoxItem): void => { | ||
| this.fetchFileEndTime = performance.now(); | ||
|
|
||
| if (this.npmPreviewLoadFailed) { | ||
| this.setState({ file }); | ||
| return; | ||
| } | ||
|
|
||
| const { file: currentFile }: State = this.state; | ||
| const isExistingFile = currentFile ? currentFile.id === file.id : false; | ||
| const isWatermarked = getProp(file, 'watermark_info.is_watermarked', false); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.