Merge pull request #8747 from overleaf/ae-error-boundary-fallback

Create a generic ErrorBoundaryFallback component

GitOrigin-RevId: 0c9200ddef2be3b90030a32eb8c36a59047cf2b4
This commit is contained in:
Alf Eaton 2022-08-09 14:48:59 +01:00 committed by Copybot
parent 9953822175
commit d905863002
11 changed files with 118 additions and 87 deletions

View file

@ -1,68 +0,0 @@
import PropTypes from 'prop-types'
import { Alert } from 'react-bootstrap'
import { Trans, useTranslation } from 'react-i18next'
function ErrorBoundaryFallback({ type }) {
const { t } = useTranslation()
// we create each instance of `<Trans/>` individually so `i18next-scanner` can detect hardcoded `i18nKey` values
let content
if (type === 'pdf') {
content = (
<>
<p>{t('pdf_viewer_error')}</p>
<p>
<Trans
i18nKey="try_recompile_project_or_troubleshoot"
components={[
// eslint-disable-next-line react/jsx-key, jsx-a11y/anchor-has-content
<a href="/learn/how-to/Resolving_access%2C_loading%2C_and_display_problems" />,
]}
/>
</p>
</>
)
} else if (type === 'logs') {
content = (
<>
<p>{t('log_viewer_error')}</p>
<p>
<Trans
i18nKey="try_recompile_project_or_troubleshoot"
components={[
// eslint-disable-next-line react/jsx-key, jsx-a11y/anchor-has-content
<a href="/learn/how-to/Resolving_access%2C_loading%2C_and_display_problems" />,
]}
/>
</p>
</>
)
} else {
content = (
<>
<p>{t('pdf_preview_error')}</p>
<p>
<Trans
i18nKey="try_recompile_project_or_troubleshoot"
components={[
// eslint-disable-next-line react/jsx-key, jsx-a11y/anchor-has-content
<a href="/learn/how-to/Resolving_access%2C_loading%2C_and_display_problems" />,
]}
/>
</p>
</>
)
}
return (
<div className="pdf-error-alert">
<Alert bsStyle="danger">{content}</Alert>
</div>
)
}
ErrorBoundaryFallback.propTypes = {
type: PropTypes.oneOf(['preview', 'pdf', 'logs']).isRequired,
}
export default ErrorBoundaryFallback

View file

@ -7,7 +7,7 @@ import usePersistedState from '../../../shared/hooks/use-persisted-state'
import { buildHighlightElement } from '../util/highlights'
import PDFJSWrapper from '../util/pdf-js-wrapper'
import withErrorBoundary from '../../../infrastructure/error-boundary'
import ErrorBoundaryFallback from './error-boundary-fallback'
import PdfPreviewErrorBoundaryFallback from './pdf-preview-error-boundary-fallback'
import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
import { captureException } from '../../../infrastructure/error-reporter'
import { getPdfCachingMetrics } from '../util/metrics'
@ -409,5 +409,5 @@ PdfJsViewer.propTypes = {
}
export default withErrorBoundary(memo(PdfJsViewer), () => (
<ErrorBoundaryFallback type="pdf" />
<PdfPreviewErrorBoundaryFallback type="pdf" />
))

View file

@ -9,7 +9,7 @@ import PdfClearCacheButton from './pdf-clear-cache-button'
import PdfDownloadFilesButton from './pdf-download-files-button'
import PdfLogsEntries from './pdf-logs-entries'
import withErrorBoundary from '../../../infrastructure/error-boundary'
import ErrorBoundaryFallback from './error-boundary-fallback'
import PdfPreviewErrorBoundaryFallback from './pdf-preview-error-boundary-fallback'
import PdfCodeCheckFailedNotice from './pdf-code-check-failed-notice'
import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
import PdfLogEntry from './pdf-log-entry'
@ -69,5 +69,5 @@ function PdfLogsViewer() {
}
export default withErrorBoundary(memo(PdfLogsViewer), () => (
<ErrorBoundaryFallback type="logs" />
<PdfPreviewErrorBoundaryFallback type="logs" />
))

View file

@ -0,0 +1,50 @@
import PropTypes from 'prop-types'
import { Trans, useTranslation } from 'react-i18next'
import { ErrorBoundaryFallback } from '../../../shared/components/error-boundary-fallback'
function PdfPreviewErrorBoundaryFallback({ type }) {
const { t } = useTranslation()
const showInfoLink = (
<Trans
i18nKey="try_recompile_project_or_troubleshoot"
components={[
// eslint-disable-next-line react/jsx-key, jsx-a11y/anchor-has-content, jsx-a11y/anchor-is-valid
<a href="/learn/how-to/Resolving_access%2C_loading%2C_and_display_problems" />,
]}
/>
)
switch (type) {
case 'pdf':
return (
<ErrorBoundaryFallback>
<p>{t('pdf_viewer_error')}</p>
<p>{showInfoLink}</p>
</ErrorBoundaryFallback>
)
case 'logs':
return (
<ErrorBoundaryFallback>
<p>{t('log_viewer_error')}</p>
<p>{showInfoLink}</p>
</ErrorBoundaryFallback>
)
case 'preview':
default:
return (
<ErrorBoundaryFallback>
<p>{t('pdf_preview_error')}</p>
<p>{showInfoLink}</p>
</ErrorBoundaryFallback>
)
}
}
PdfPreviewErrorBoundaryFallback.propTypes = {
type: PropTypes.oneOf(['preview', 'pdf', 'logs']).isRequired,
}
export default PdfPreviewErrorBoundaryFallback

View file

@ -2,7 +2,7 @@ import PdfPreviewPane from './pdf-preview-pane'
import useCompileTriggers from '../hooks/use-compile-triggers'
import { memo } from 'react'
import withErrorBoundary from '../../../infrastructure/error-boundary'
import ErrorBoundaryFallback from './error-boundary-fallback'
import PdfPreviewErrorBoundaryFallback from './pdf-preview-error-boundary-fallback'
import { useLayoutContext } from '../../../shared/context/layout-context'
function PdfPreview() {
@ -14,5 +14,5 @@ function PdfPreview() {
}
export default withErrorBoundary(memo(PdfPreview), () => (
<ErrorBoundaryFallback type="preview" />
<PdfPreviewErrorBoundaryFallback type="preview" />
))

View file

@ -0,0 +1,21 @@
import { FC, ReactNode } from 'react'
import { Alert } from 'react-bootstrap'
import { useTranslation } from 'react-i18next'
export const ErrorBoundaryFallback: FC<{ modal?: ReactNode }> = ({
children,
modal,
}) => {
return (
<div className="error-boundary-alert">
<Alert bsStyle="danger">{children || <DefaultContent />}</Alert>
{modal}
</div>
)
}
const DefaultContent = () => {
const { t } = useTranslation()
return <p>{`${t('generic_something_went_wrong')}. ${t('please_refresh')}`}</p>
}

View file

@ -0,0 +1,28 @@
import importOverleafModules from '../../../macros/import-overleaf-module.macro'
import { JSXElementConstructor, useCallback, useState } from 'react'
const [contactUsModalModules] = importOverleafModules('contactUsModal')
const ContactUsModal: JSXElementConstructor<{
show: boolean
handleHide: () => void
}> = contactUsModalModules?.import.default
export const useContactUsModal = () => {
const [show, setShow] = useState(false)
const hideModal = useCallback((event?: Event) => {
event?.preventDefault()
setShow(false)
}, [])
const showModal = useCallback((event?: Event) => {
event?.preventDefault()
setShow(true)
}, [])
const modal = ContactUsModal && (
<ContactUsModal show={show} handleHide={hideModal} />
)
return { modal, hideModal, showModal }
}

View file

@ -1,20 +1,20 @@
import ErrorBoundaryFallback from '../js/features/pdf-preview/components/error-boundary-fallback'
import PdfPreviewErrorBoundaryFallback from '../js/features/pdf-preview/components/pdf-preview-error-boundary-fallback'
import { ScopeDecorator } from './decorators/scope'
export default {
title: 'Editor / PDF Preview / Error Boundary',
component: ErrorBoundaryFallback,
component: PdfPreviewErrorBoundaryFallback,
decorators: [ScopeDecorator],
}
export const PreviewErrorBoundary = () => {
return <ErrorBoundaryFallback type="preview" />
return <PdfPreviewErrorBoundaryFallback type="preview" />
}
export const PdfErrorBoundary = () => {
return <ErrorBoundaryFallback type="pdf" />
return <PdfPreviewErrorBoundaryFallback type="pdf" />
}
export const LogsErrorBoundary = () => {
return <ErrorBoundaryFallback type="logs" />
return <PdfPreviewErrorBoundaryFallback type="logs" />
}

View file

@ -3,6 +3,7 @@
@import './editor/toolbar.less';
@import './editor/left-menu.less';
@import './editor/pdf.less';
@import './editor/error-boundary.less';
@import './editor/share.less';
@import './editor/chat.less';
@import './editor/file-view.less';

View file

@ -0,0 +1,7 @@
.error-boundary-alert {
position: absolute;
width: 100%;
height: 100%;
background-color: @ol-blue-gray-0;
padding: @line-height-computed / 2;
}

View file

@ -649,14 +649,6 @@
);
}
.pdf-error-alert {
position: absolute;
width: 100%;
height: 100%;
background-color: @pdf-bg;
padding: @line-height-computed / 2;
}
.pdf-loading-spinner-container {
width: 100%;
height: 100%;