Merge pull request #33972 from overleaf/mj-web-show-pandoc-error

[web] Expose conversion errors during project exports

GitOrigin-RevId: 2e808bd65f03e81405db4727f2f5773d3b14cbe7
This commit is contained in:
Mathias Jakobsen
2026-05-28 08:08:14 +00:00
committed by Copybot
parent e7a202a0bf
commit 51ca5c0156
11 changed files with 281 additions and 17 deletions
@@ -6,8 +6,11 @@ const PreparingExportToast = () => {
return <span>{t('preparing_for_export')}</span>
}
const ExportDocumentErrorToast = () => {
const ExportDocumentErrorToast = ({ data }: { data?: any }) => {
const { t } = useTranslation()
const errorMessage =
typeof data?.errorMessage === 'string' ? data.errorMessage : null
return (
<>
<p>
@@ -20,6 +23,16 @@ const ExportDocumentErrorToast = () => {
<a href="/contact" target="_BLANK" rel="noopener noreferrer" />,
]}
/>
{errorMessage && (
<details>
<summary>{t('error_details')}</summary>
<pre
style={{ maxWidth: '800px', maxHeight: '300px', overflow: 'auto' }}
>
<code>{errorMessage}</code>
</pre>
</details>
)}
</>
)
}
@@ -70,10 +83,11 @@ const ExportDocumentSuccessToast = ({ data }: { data?: any }) => {
const generators: GlobalToastGeneratorEntry[] = [
{
key: 'export-document:error',
generator: () => ({
content: <ExportDocumentErrorToast />,
generator: (data: any) => ({
content: <ExportDocumentErrorToast data={data} />,
type: 'error',
autoHide: true,
// Only auto-hide if we have no extra details
autoHide: !data?.errorMessage,
delay: 5000,
isDismissible: true,
}),
@@ -101,10 +115,25 @@ const generators: GlobalToastGeneratorEntry[] = [
export default generators
export const showExportDocumentError = () => {
// We only ever care about the latest error toast, so use a static handle.
const EXPORT_DOCUMENT_ERROR_HANDLE = 'export-document-error'
export const showExportDocumentError = (errorMessage?: string) => {
window.dispatchEvent(
new CustomEvent('ide:show-toast', {
detail: { key: 'export-document:error' },
detail: {
key: 'export-document:error',
handle: EXPORT_DOCUMENT_ERROR_HANDLE,
errorMessage,
},
})
)
}
export const hideExportDocumentError = () => {
window.dispatchEvent(
new CustomEvent('ide:dismiss-toast', {
detail: { handle: EXPORT_DOCUMENT_ERROR_HANDLE },
})
)
}
@@ -1,9 +1,10 @@
import { getJSON } from '@/infrastructure/fetch-json'
import { FetchError, getJSON } from '@/infrastructure/fetch-json'
import { useLocation } from '@/shared/hooks/use-location'
import { debugConsole } from '@/utils/debugging'
import { useProjectContext } from '@/shared/context/project-context'
import { useCallback } from 'react'
import {
hideExportDocumentError,
hidePreparingExportToast,
showExportDocumentError,
showExportDocumentSuccess,
@@ -35,6 +36,7 @@ export default function useConvertProject(
url.searchParams.set('responseFormat', 'json')
const { rootResourcePath } = getRootDocInfo()
url.searchParams.set('rootResourcePath', rootResourcePath)
hideExportDocumentError()
try {
await openDocs.awaitBufferedOps(AbortSignal.timeout(10_000))
const response = await getJSON(url.href)
@@ -49,7 +51,15 @@ export default function useConvertProject(
}
} catch (error) {
hidePreparingToast()
showExportDocumentError()
let errorMessage
if (
error instanceof FetchError &&
error.response?.status === 422 &&
error.data?.error
) {
errorMessage = error.data.error
}
showExportDocumentError(errorMessage)
debugConsole.error(error)
}
}, [projectId, type, getRootDocInfo, openDocs, location])