Merge pull request #34102 from overleaf/mj-document-import-errors
[web] Expose pandoc errors in import GitOrigin-RevId: 55f89b91a52099a99a5d955bc05f3657b87b2cdc
This commit is contained in:
committed by
Copybot
parent
97247b8ea5
commit
cabe0046c5
@@ -188,7 +188,10 @@ async function importDocument(req, res, next) {
|
||||
const { path } = req.file
|
||||
const conversionType = req.query.type
|
||||
if (!['docx', 'markdown'].includes(conversionType)) {
|
||||
return res.status(400).json({ success: false, error: 'invalid_type' })
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: req.i18n.translate('invalid_import_type'),
|
||||
})
|
||||
}
|
||||
const name = Path.basename(req.body.name, Path.extname(req.body.name))
|
||||
logger.debug({ path, userId, conversionType }, 'importing document file')
|
||||
@@ -239,7 +242,7 @@ async function importDocument(req, res, next) {
|
||||
) {
|
||||
return res.status(422).json({
|
||||
success: false,
|
||||
error: 'file_too_large',
|
||||
error: req.i18n.translate('file_too_large'),
|
||||
})
|
||||
}
|
||||
if (error instanceof DocumentConversionError) {
|
||||
|
||||
@@ -2488,6 +2488,7 @@
|
||||
"your_current_plan_gives_you": "",
|
||||
"your_current_plan_supports_up_to_x_licenses": "",
|
||||
"your_current_project_will_revert_to_the_version_from_time": "",
|
||||
"your_document_couldnt_be_imported_check_our_guidance_or_expand_conversion_error_details": "",
|
||||
"your_email_is_confirmed": "",
|
||||
"your_feedback_matters_answer_two_quick_questions": "",
|
||||
"your_git_access_info": "",
|
||||
|
||||
+48
-3
@@ -1,6 +1,6 @@
|
||||
import { useMemo } from 'react'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { Dashboard } from '@uppy/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { useProjectUploader } from '../../hooks/use-project-uploader'
|
||||
import {
|
||||
OLModal,
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
import OLButton from '@/shared/components/ol/ol-button'
|
||||
import '@uppy/core/dist/style.css'
|
||||
import '@uppy/dashboard/dist/style.css'
|
||||
import OLNotification from '@/shared/components/ol/ol-notification'
|
||||
|
||||
function ImportDocumentModal({
|
||||
type,
|
||||
@@ -23,6 +24,7 @@ function ImportDocumentModal({
|
||||
openProject: (id: string, convertedFrom?: string) => void
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const IMPORT_CONFIGS = useMemo(
|
||||
() => ({
|
||||
docx: {
|
||||
@@ -46,6 +48,18 @@ function ImportDocumentModal({
|
||||
endpoint: `/project/new/import-document?type=${type}`,
|
||||
allowedFileTypes: config.allowedFileTypes,
|
||||
onSuccess: (projectId: string) => openProject(projectId, type),
|
||||
onError: response => {
|
||||
const message = response?.body?.error
|
||||
if (message) {
|
||||
setError(message)
|
||||
}
|
||||
},
|
||||
onFileAdded: () => {
|
||||
setError(null)
|
||||
},
|
||||
onFileRemoved: () => {
|
||||
setError(null)
|
||||
},
|
||||
})
|
||||
|
||||
return (
|
||||
@@ -56,11 +70,11 @@ function ImportDocumentModal({
|
||||
id="upload-project-modal"
|
||||
backdrop="static"
|
||||
>
|
||||
{/* TODO: make necessary changes here for import document modal */}
|
||||
<OLModalHeader>
|
||||
<OLModalTitle as="h3">{config.title}</OLModalTitle>
|
||||
</OLModalHeader>
|
||||
<OLModalBody>
|
||||
{error && <ErrorNotification message={error} />}
|
||||
<p>{t('import_document_description')}</p>
|
||||
<Dashboard
|
||||
uppy={uppy}
|
||||
@@ -87,4 +101,35 @@ function ImportDocumentModal({
|
||||
)
|
||||
}
|
||||
|
||||
const ErrorNotification = ({ message }: { message: string }) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<OLNotification
|
||||
type="error"
|
||||
className="import-error-notification"
|
||||
content={
|
||||
<div>
|
||||
<Trans
|
||||
i18nKey="your_document_couldnt_be_imported_check_our_guidance_or_expand_conversion_error_details"
|
||||
components={[
|
||||
// eslint-disable-next-line react/jsx-key, jsx-a11y/anchor-has-content
|
||||
<a
|
||||
href="https://docs.overleaf.com/managing-projects-and-files/importing-and-exporting-files#common-issues-and-how-to-address-them"
|
||||
target="_BLANK"
|
||||
rel="noopener noreferrer"
|
||||
/>,
|
||||
]}
|
||||
/>
|
||||
{message && (
|
||||
<details style={{ maxHeight: '200px', overflow: 'auto' }}>
|
||||
<summary>{t('conversion_error_details')}</summary>
|
||||
<code style={{ wordBreak: 'break-all' }}>{message}</code>
|
||||
</details>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default ImportDocumentModal
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import Uppy from '@uppy/core'
|
||||
import Uppy, { ErrorResponse } from '@uppy/core'
|
||||
import XHRUpload from '@uppy/xhr-upload'
|
||||
import getMeta from '@/utils/meta'
|
||||
|
||||
@@ -7,6 +7,9 @@ type UploaderConfig = {
|
||||
endpoint: string
|
||||
allowedFileTypes: string[]
|
||||
onSuccess: (projectId: string) => void
|
||||
onError?: (response: ErrorResponse | undefined) => void
|
||||
onFileAdded?: () => void
|
||||
onFileRemoved?: () => void
|
||||
}
|
||||
|
||||
type ImportResponse = {
|
||||
@@ -17,6 +20,9 @@ export function useProjectUploader({
|
||||
endpoint,
|
||||
allowedFileTypes,
|
||||
onSuccess,
|
||||
onError,
|
||||
onFileAdded,
|
||||
onFileRemoved,
|
||||
}: UploaderConfig) {
|
||||
const { maxUploadSize, projectUploadTimeout } = getMeta('ol-ExposedSettings')
|
||||
const [ableToUpload, setAbleToUpload] = useState(false)
|
||||
@@ -47,9 +53,10 @@ export function useProjectUploader({
|
||||
// the rest of the files will appear on the 'restriction-failed' event callback
|
||||
setAbleToUpload(true)
|
||||
})
|
||||
.on('upload-error', () => {
|
||||
.on('upload-error', (_file, _err, response) => {
|
||||
// refresh state so they can try uploading a new file
|
||||
setAbleToUpload(false)
|
||||
onError?.(response)
|
||||
})
|
||||
.on('upload-success', (_file, response) => {
|
||||
const { project_id: projectId }: ImportResponse = response.body
|
||||
@@ -70,6 +77,12 @@ export function useProjectUploader({
|
||||
// reset state so they can try uploading a different file, etc
|
||||
setAbleToUpload(false)
|
||||
})
|
||||
.on('file-added', () => {
|
||||
onFileAdded?.()
|
||||
})
|
||||
.on('file-removed', () => {
|
||||
onFileRemoved?.()
|
||||
})
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1283,6 +1283,7 @@
|
||||
"invalid_email": "An email address is invalid",
|
||||
"invalid_file_name": "Invalid File Name",
|
||||
"invalid_filename": "Upload failed: check that the file name doesn’t contain special characters, trailing/leading whitespace or more than __nameLimit__ characters",
|
||||
"invalid_import_type": "Invalid import type",
|
||||
"invalid_institutional_email": "Your institution’s SSO service returned your email address as __email__, which is an unexpected domain that we do not recognise as belonging to it. You may be able to change your primary email address via your user profile at your institution to one at your institution’s domain. Please contact your IT department if you have any questions.",
|
||||
"invalid_organization_email": "Your organization’s SSO service returned your email address as <0>__institutionEmail__</0>, which is an unexpected domain that we do not recognise as belonging to it. Please <1>contact us</1> if you think this is in error.",
|
||||
"invalid_password": "Invalid Password.",
|
||||
@@ -3154,6 +3155,7 @@
|
||||
"your_current_plan_gives_you": "By pausing your subscription, you’ll be able to access your premium features faster when you need them again.",
|
||||
"your_current_plan_supports_up_to_x_licenses": "Your current plan supports up to __users__ licenses.",
|
||||
"your_current_project_will_revert_to_the_version_from_time": "Your current project will revert to the version from __timestamp__",
|
||||
"your_document_couldnt_be_imported_check_our_guidance_or_expand_conversion_error_details": "Your document couldn’t be imported. <0>Check our guidance on common import problems</0> or expand the conversion error details below.",
|
||||
"your_email_is_confirmed": "Your email is confirmed.",
|
||||
"your_email_is_not_set_up_with_sso": "Your email is not set up with __institutionName__ SSO. Please log in with your existing login method to confirm your identity.",
|
||||
"your_feedback_matters_answer_two_quick_questions": "Your feedback matters! Answer two quick questions.",
|
||||
|
||||
@@ -636,7 +636,7 @@ describe('ProjectUploadController', function () {
|
||||
ctx.res.json = data => {
|
||||
expect(data).to.deep.equal({
|
||||
success: false,
|
||||
error: 'invalid_type',
|
||||
error: 'invalid_import_type',
|
||||
})
|
||||
resolve()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user