Merge pull request #33341 from overleaf/mj-two-step-export-web

[web] Add two-step pandoc conversion download

GitOrigin-RevId: 093f435a497a7583d2b4d23558415cc442f84553
This commit is contained in:
Mathias Jakobsen
2026-05-12 08:06:13 +00:00
committed by Copybot
parent 64d706f114
commit 62d92b70dd
12 changed files with 554 additions and 82 deletions
@@ -9,6 +9,7 @@ import { useTranslation } from 'react-i18next'
import { useEditorAnalytics } from '@/shared/hooks/use-editor-analytics'
import getMeta from '@/utils/meta'
import { useFeatureFlag } from '@/shared/context/split-test-context'
import useConvertProject from '../../hooks/use-convert-project'
export const DownloadProjectZip = () => {
const { t } = useTranslation()
@@ -105,11 +106,11 @@ export const DownloadProjectPDF = () => {
export const ExportProjectDocx = () => {
const { t } = useTranslation()
const { projectId } = useProjectContext()
const exportDocxEnabled = useFeatureFlag('export-docx')
const enablePandocConversions =
getMeta('ol-ExposedSettings')?.enablePandocConversions
const anonymous = getMeta('ol-anonymous')
const downloadConversion = useConvertProject('docx')
const showExportDocx =
exportDocxEnabled && enablePandocConversions && !anonymous
@@ -120,12 +121,12 @@ export const ExportProjectDocx = () => {
? [
{
id: 'export-as-docx',
href: `/project/${projectId}/download/conversion/docx`,
handler: downloadConversion,
label: t('export_as_docx'),
},
]
: [],
[t, showExportDocx, projectId]
[t, showExportDocx, downloadConversion]
)
if (!showExportDocx) {
@@ -133,11 +134,7 @@ export const ExportProjectDocx = () => {
}
return (
<OLDropdownMenuItem
href={`/project/${projectId}/download/conversion/docx`}
target="_blank"
rel="noreferrer"
>
<OLDropdownMenuItem onClick={downloadConversion}>
{t('export_as_docx')}
</OLDropdownMenuItem>
)
@@ -145,11 +142,11 @@ export const ExportProjectDocx = () => {
export const ExportProjectMarkdown = () => {
const { t } = useTranslation()
const { projectId } = useProjectContext()
const exportMarkdownEnabled = useFeatureFlag('export-markdown')
const enablePandocConversions =
getMeta('ol-ExposedSettings')?.enablePandocConversions
const anonymous = getMeta('ol-anonymous')
const downloadConversion = useConvertProject('markdown')
const showExportMarkdown =
exportMarkdownEnabled && enablePandocConversions && !anonymous
@@ -160,12 +157,12 @@ export const ExportProjectMarkdown = () => {
? [
{
id: 'export-as-markdown',
href: `/project/${projectId}/download/conversion/markdown`,
handler: downloadConversion,
label: t('export_as_markdown'),
},
]
: [],
[t, showExportMarkdown, projectId]
[t, showExportMarkdown, downloadConversion]
)
if (!showExportMarkdown) {
@@ -173,11 +170,7 @@ export const ExportProjectMarkdown = () => {
}
return (
<OLDropdownMenuItem
href={`/project/${projectId}/download/conversion/markdown`}
target="_blank"
rel="noreferrer"
>
<OLDropdownMenuItem onClick={downloadConversion}>
{t('export_as_markdown')}
</OLDropdownMenuItem>
)
@@ -1,9 +1,27 @@
import { GlobalToastGeneratorEntry } from '@/features/ide-react/components/global-toasts'
import { useTranslation } from 'react-i18next'
import { Trans, useTranslation } from 'react-i18next'
const PreparingExportToast = () => {
const { t } = useTranslation()
return <span>{t('preparing_for_export')}</span>
}
const ExportDocumentErrorToast = () => {
const { t } = useTranslation()
return <span>{t('export_document_error')}</span>
return (
<>
<p>
<b>{t('we_couldnt_export_this_document')}</b>
</p>
<Trans
i18nKey="the_document_contains_formatting_we_werent_able_to_convert_contact_support_if_you_need_help"
components={[
// eslint-disable-next-line react/jsx-key, jsx-a11y/anchor-has-content
<a href="/contact" target="_BLANK" rel="noopener noreferrer" />,
]}
/>
</>
)
}
const generators: GlobalToastGeneratorEntry[] = [
@@ -17,6 +35,41 @@ const generators: GlobalToastGeneratorEntry[] = [
isDismissible: true,
}),
},
{
key: 'export-document:preparing',
generator: () => ({
content: <PreparingExportToast />,
type: 'info',
autoHide: false,
isDismissible: true,
}),
},
]
export default generators
export const showExportDocumentError = () => {
window.dispatchEvent(
new CustomEvent('ide:show-toast', {
detail: { key: 'export-document:error' },
})
)
}
export const showPreparingExportToast = () => {
const handle = `export-document-preparing-${Date.now()}`
window.dispatchEvent(
new CustomEvent('ide:show-toast', {
detail: { key: 'export-document:preparing', handle },
})
)
return handle
}
export const hidePreparingExportToast = (handle: string) => {
window.dispatchEvent(
new CustomEvent('ide:dismiss-toast', {
detail: { key: 'export-document:preparing', handle },
})
)
}