pdf-preview-error.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. import { useTranslation, Trans } from 'react-i18next'
  2. import { memo, useCallback } from 'react'
  3. import OLButton from '@/shared/components/ol/ol-button'
  4. import PdfLogEntry from './pdf-log-entry'
  5. import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
  6. import { useStopOnFirstError } from '../../../shared/hooks/use-stop-on-first-error'
  7. import getMeta from '../../../utils/meta'
  8. import { sendMB } from '@/infrastructure/event-tracking'
  9. function PdfPreviewError({
  10. error,
  11. includeWarnings = true,
  12. includeErrors = true,
  13. }: {
  14. error: string
  15. includeWarnings?: boolean
  16. includeErrors?: boolean
  17. }) {
  18. const { t } = useTranslation()
  19. const { startCompile } = useCompileContext()
  20. switch (error) {
  21. case 'rendering-error-expected':
  22. return (
  23. includeWarnings && (
  24. <PdfLogEntry
  25. headerTitle={t('pdf_rendering_error')}
  26. formattedContent={
  27. <>
  28. <Trans
  29. i18nKey="something_went_wrong_rendering_pdf_expected"
  30. components={[
  31. // eslint-disable-next-line react/jsx-key
  32. <OLButton
  33. variant="primary"
  34. size="sm"
  35. onClick={() => startCompile()}
  36. />,
  37. ]}
  38. />
  39. <br />
  40. <br />
  41. <Trans
  42. i18nKey="last_resort_trouble_shooting_guide"
  43. components={[
  44. // eslint-disable-next-line jsx-a11y/anchor-has-content
  45. <a
  46. href="/learn/how-to/Resolving_access%2C_loading%2C_and_display_problems"
  47. target="_blank"
  48. key="troubleshooting-link"
  49. />,
  50. ]}
  51. />
  52. </>
  53. }
  54. level="warning"
  55. />
  56. )
  57. )
  58. case 'rendering-error':
  59. return (
  60. includeErrors && (
  61. <ErrorLogEntry title={t('pdf_rendering_error')}>
  62. {t('something_went_wrong_rendering_pdf')}
  63. &nbsp;
  64. <Trans
  65. i18nKey="try_recompile_project_or_troubleshoot"
  66. components={[
  67. // eslint-disable-next-line jsx-a11y/anchor-has-content
  68. <a
  69. href="/learn/how-to/Resolving_access%2C_loading%2C_and_display_problems"
  70. target="_blank"
  71. key="troubleshooting-link"
  72. />,
  73. ]}
  74. />
  75. {getMeta('ol-compilesUserContentDomain') && (
  76. <>
  77. <br />
  78. <br />
  79. <Trans
  80. i18nKey="new_compile_domain_notice"
  81. values={{
  82. compilesUserContentDomain: new URL(
  83. getMeta('ol-compilesUserContentDomain')
  84. ).hostname,
  85. }}
  86. shouldUnescape
  87. tOptions={{ interpolation: { escapeValue: true } }}
  88. components={[
  89. <code key="domain" />,
  90. /* eslint-disable-next-line jsx-a11y/anchor-has-content */
  91. <a
  92. href="/learn/how-to/Resolving_access%2C_loading%2C_and_display_problems"
  93. target="_blank"
  94. key="troubleshooting-link"
  95. />,
  96. ]}
  97. />
  98. </>
  99. )}
  100. </ErrorLogEntry>
  101. )
  102. )
  103. case 'clsi-maintenance':
  104. return (
  105. includeErrors && (
  106. <ErrorLogEntry title={t('server_error')}>
  107. {t('clsi_maintenance')}
  108. </ErrorLogEntry>
  109. )
  110. )
  111. case 'clsi-unavailable':
  112. return (
  113. includeErrors && (
  114. <ErrorLogEntry title={t('server_error')}>
  115. {t('clsi_unavailable')}
  116. </ErrorLogEntry>
  117. )
  118. )
  119. case 'too-recently-compiled':
  120. return (
  121. includeErrors && (
  122. <ErrorLogEntry title={t('server_error')}>
  123. {t('too_recently_compiled')}
  124. </ErrorLogEntry>
  125. )
  126. )
  127. case 'terminated':
  128. return (
  129. includeErrors && (
  130. <ErrorLogEntry title={t('terminated')}>
  131. {t('compile_terminated_by_user')}
  132. </ErrorLogEntry>
  133. )
  134. )
  135. case 'rate-limited':
  136. return (
  137. includeErrors && (
  138. <ErrorLogEntry title={t('pdf_compile_rate_limit_hit')}>
  139. {t('project_flagged_too_many_compiles')}
  140. </ErrorLogEntry>
  141. )
  142. )
  143. case 'compile-in-progress':
  144. return (
  145. includeErrors && (
  146. <ErrorLogEntry title={t('pdf_compile_in_progress_error')}>
  147. {t('pdf_compile_try_again')}
  148. </ErrorLogEntry>
  149. )
  150. )
  151. case 'autocompile-disabled':
  152. return (
  153. includeErrors && (
  154. <ErrorLogEntry title={t('autocompile_disabled')}>
  155. {t('autocompile_disabled_reason')}
  156. </ErrorLogEntry>
  157. )
  158. )
  159. case 'project-too-large':
  160. return (
  161. includeErrors && (
  162. <ErrorLogEntry title={t('project_too_large')}>
  163. {t('project_too_much_editable_text')}
  164. </ErrorLogEntry>
  165. )
  166. )
  167. case 'timedout':
  168. return includeErrors && <TimedOutLogEntry />
  169. case 'failure':
  170. return (
  171. includeErrors && (
  172. <ErrorLogEntry title={t('no_pdf_error_title')}>
  173. {t('no_pdf_error_explanation')}
  174. <ul className="my-1 ps-3">
  175. <li>{t('no_pdf_error_reason_unrecoverable_error')}</li>
  176. <li>
  177. <Trans
  178. i18nKey="no_pdf_error_reason_no_content"
  179. components={{ code: <code /> }}
  180. />
  181. </li>
  182. <li>
  183. <Trans
  184. i18nKey="no_pdf_error_reason_output_pdf_already_exists"
  185. components={{ code: <code /> }}
  186. />
  187. </li>
  188. </ul>
  189. </ErrorLogEntry>
  190. )
  191. )
  192. case 'clear-cache':
  193. return (
  194. includeErrors && (
  195. <ErrorLogEntry title={t('server_error')}>
  196. {t('somthing_went_wrong_compiling')}
  197. </ErrorLogEntry>
  198. )
  199. )
  200. case 'pdf-viewer-loading-error':
  201. return (
  202. includeErrors && (
  203. <ErrorLogEntry title={t('pdf_rendering_error')}>
  204. <Trans
  205. i18nKey="something_went_wrong_loading_pdf_viewer"
  206. components={[
  207. <strong key="strong-" />,
  208. // eslint-disable-next-line jsx-a11y/anchor-has-content
  209. <a
  210. href="/learn/how-to/Resolving_access%2C_loading%2C_and_display_problems"
  211. target="_blank"
  212. key="troubleshooting-link"
  213. />,
  214. // eslint-disable-next-line jsx-a11y/anchor-has-content
  215. <a key="contact-link" target="_blank" href="/contact" />,
  216. ]}
  217. />
  218. </ErrorLogEntry>
  219. )
  220. )
  221. case 'validation-problems':
  222. return null // handled elsewhere
  223. case 'error':
  224. default:
  225. return (
  226. includeErrors && (
  227. <ErrorLogEntry title={t('server_error')}>
  228. {t('somthing_went_wrong_compiling')}
  229. </ErrorLogEntry>
  230. )
  231. )
  232. }
  233. }
  234. export default memo(PdfPreviewError)
  235. function ErrorLogEntry({
  236. autoExpand,
  237. title,
  238. headerIcon,
  239. children,
  240. }: {
  241. autoExpand?: boolean
  242. title: string
  243. headerIcon?: React.ReactElement
  244. children: React.ReactNode
  245. }) {
  246. const { t } = useTranslation()
  247. return (
  248. <PdfLogEntry
  249. autoExpand={autoExpand}
  250. headerTitle={title}
  251. headerIcon={headerIcon}
  252. formattedContent={children}
  253. entryAriaLabel={t('compile_error_entry_description')}
  254. level="error"
  255. />
  256. )
  257. }
  258. function TimedOutLogEntry() {
  259. const { t } = useTranslation()
  260. const { enableStopOnFirstError } = useStopOnFirstError({
  261. eventSource: 'timeout',
  262. })
  263. const { startCompile, lastCompileOptions, setAnimateCompileDropdownArrow } =
  264. useCompileContext()
  265. const handleEnableStopOnFirstErrorClick = useCallback(() => {
  266. enableStopOnFirstError()
  267. startCompile({ stopOnFirstError: true })
  268. setAnimateCompileDropdownArrow(true)
  269. }, [enableStopOnFirstError, startCompile, setAnimateCompileDropdownArrow])
  270. return (
  271. <ErrorLogEntry autoExpand title={t('timedout')}>
  272. <p>{t('project_timed_out_intro')}</p>
  273. <ul>
  274. <li>
  275. <Trans
  276. i18nKey="project_timed_out_optimize_images"
  277. components={[
  278. // eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
  279. <a
  280. href="https://www.overleaf.com/learn/how-to/Optimising_very_large_image_files"
  281. onClick={() => {
  282. sendMB('paywall-info-click', {
  283. 'paywall-type': 'compile-timeout',
  284. content: 'docs',
  285. type: 'optimize',
  286. })
  287. }}
  288. />,
  289. ]}
  290. />
  291. </li>
  292. <li>
  293. <Trans
  294. i18nKey="project_timed_out_fatal_error"
  295. components={[
  296. // eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
  297. <a
  298. href="https://www.overleaf.com/learn/how-to/Why_do_I_keep_getting_the_compile_timeout_error_message%3F#Fatal_compile_errors_blocking_the_compilation"
  299. onClick={() => {
  300. sendMB('paywall-info-click', {
  301. 'paywall-type': 'compile-timeout',
  302. content: 'docs',
  303. type: 'fatal-error',
  304. })
  305. }}
  306. />,
  307. ]}
  308. />
  309. {!lastCompileOptions.stopOnFirstError && (
  310. <>
  311. {' '}
  312. <Trans
  313. i18nKey="project_timed_out_enable_stop_on_first_error"
  314. components={[
  315. // eslint-disable-next-line react/jsx-key
  316. <OLButton
  317. variant="primary"
  318. size="sm"
  319. onClick={handleEnableStopOnFirstErrorClick}
  320. />,
  321. ]}
  322. />{' '}
  323. </>
  324. )}
  325. </li>
  326. </ul>
  327. <p>
  328. <Trans
  329. i18nKey="project_timed_out_learn_more"
  330. components={[
  331. // eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
  332. <a
  333. href="https://www.overleaf.com/learn/how-to/Why_do_I_keep_getting_the_compile_timeout_error_message%3F"
  334. onClick={() => {
  335. sendMB('paywall-info-click', {
  336. 'paywall-type': 'compile-timeout',
  337. content: 'docs',
  338. type: 'learn-more',
  339. })
  340. }}
  341. />,
  342. ]}
  343. />
  344. </p>
  345. </ErrorLogEntry>
  346. )
  347. }