Просмотр исходного кода

Merge pull request #28037 from overleaf/dp-additional-error-states

Add additional pdf error states in new editor

GitOrigin-RevId: a7e08652cb5ff23d2139106629f13aad20bd32a0
David 1 год назад
Родитель
Сommit
76e23434ed

+ 3 - 132
services/web/frontend/js/features/ide-redesign/components/pdf-preview/pdf-error-state.tsx → services/web/frontend/js/features/ide-redesign/components/pdf-preview/pdf-error-state/compile-timeout-error-state.tsx

@@ -1,103 +1,13 @@
 import OLButton from '@/shared/components/ol/ol-button'
 import MaterialIcon from '@/shared/components/material-icon'
 import { Trans, useTranslation } from 'react-i18next'
-import { useRailContext } from '../../contexts/rail-context'
-import { usePdfPreviewContext } from '@/features/pdf-preview/components/pdf-preview-provider'
 import { useDetachCompileContext as useCompileContext } from '@/shared/context/detach-compile-context'
-import { useIsNewEditorEnabled } from '../../utils/new-editor-utils'
 import { upgradePlan } from '@/main/account-upgrade'
-import classNames from 'classnames'
 import { useStopOnFirstError } from '@/shared/hooks/use-stop-on-first-error'
 import { useCallback } from 'react'
+import ErrorState from './error-state'
 
-// AvailableStates
-// - rendering-error-expected
-// - rendering-error
-// - clsi-maintenance
-// - clsi-unavailable
-// - too-recently-compiled
-// - terminated
-// - rate-limited
-// - compile-in-progress
-// - autocompile-disabled
-// - project-too-large
-// - timedout
-// - failure
-// - clear-cache
-// - pdf-viewer-loading-error
-// - validation-problems
-function PdfErrorState() {
-  const { loadingError } = usePdfPreviewContext()
-  // TODO ide-redesign-cleanup: rename showLogs to something else and check usages
-  const { hasShortCompileTimeout, error, showLogs } = useCompileContext()
-  const newEditor = useIsNewEditorEnabled()
-  const { t } = useTranslation()
-
-  if (!newEditor || (!loadingError && !showLogs)) {
-    return null
-  }
-
-  switch (error) {
-    case 'timedout': {
-      if (hasShortCompileTimeout) {
-        return <CompileTimeoutErrorState />
-      } else {
-        return <LongCompileTimeoutErrorState />
-      }
-    }
-    case 'compile-in-progress':
-      return (
-        <ErrorState
-          title={t('pdf_compile_in_progress_error')}
-          description={t('pdf_compile_try_again')}
-          iconType="warning"
-        />
-      )
-    default:
-      return <GeneralErrorState />
-  }
-}
-
-const GeneralErrorState = () => {
-  const { t } = useTranslation()
-  const { openTab: openRailTab } = useRailContext()
-
-  return (
-    <ErrorState
-      title={t('pdf_couldnt_compile')}
-      description={t('we_are_unable_to_generate_the_pdf_at_this_time')}
-      iconType="warning"
-      actions={
-        <OLButton
-          variant="secondary"
-          size="sm"
-          onClick={() => {
-            openRailTab('errors')
-          }}
-        >
-          {t('check_logs')}
-        </OLButton>
-      }
-      extraContent={
-        <div className="pdf-error-state-info-box">
-          <div className="pdf-error-state-info-box-title">
-            <MaterialIcon type="info" unfilled />
-            {t('why_might_this_happen')}
-          </div>
-          <div className="pdf-error-state-info-box-text">
-            <ul className="pdf-error-state-info-box-list">
-              <li>{t('there_is_an_unrecoverable_latex_error_check_logs')}</li>
-              <li>{t('the_document_environment_contains_no_content')}</li>
-              <li>{t('this_project_contains_a_file_called_output')}</li>
-            </ul>
-          </div>
-        </div>
-      }
-    />
-  )
-}
-
-const CompileTimeoutErrorState = () => {
+export const ShortCompileTimeoutErrorState = () => {
   const { t } = useTranslation()
 
   return (
@@ -118,7 +28,7 @@ const CompileTimeoutErrorState = () => {
   )
 }
 
-const LongCompileTimeoutErrorState = () => {
+export const LongCompileTimeoutErrorState = () => {
   const { t } = useTranslation()
 
   const { enableStopOnFirstError } = useStopOnFirstError({
@@ -196,42 +106,3 @@ const LongCompileTimeoutErrorState = () => {
     />
   )
 }
-
-const ErrorState = ({
-  title,
-  description,
-  iconType,
-  actions,
-  iconClassName,
-  extraContent,
-}: {
-  title: string
-  description: string
-  iconType: string
-  actions?: React.ReactNode
-  iconClassName?: string
-  extraContent?: React.ReactNode
-}) => {
-  return (
-    <div className="pdf-error-state">
-      <div className="pdf-error-state-top-section">
-        <div
-          className={classNames(
-            'pdf-error-state-icon',
-            'pdf-error-state-warning-icon',
-            iconClassName
-          )}
-        >
-          <MaterialIcon type={iconType} />
-        </div>
-        <div className="pdf-error-state-text">
-          <p className="pdf-error-state-label">{title}</p>
-          <p className="pdf-error-state-description">{description}</p>
-        </div>
-        {actions}
-      </div>
-      {extraContent}
-    </div>
-  )
-}
-export default PdfErrorState

+ 60 - 0
services/web/frontend/js/features/ide-redesign/components/pdf-preview/pdf-error-state/error-state.tsx

@@ -0,0 +1,60 @@
+import { useRailContext } from '@/features/ide-redesign/contexts/rail-context'
+import MaterialIcon from '@/shared/components/material-icon'
+import OLButton from '@/shared/components/ol/ol-button'
+import classNames from 'classnames'
+import { useTranslation } from 'react-i18next'
+
+export default function ErrorState({
+  title,
+  description,
+  iconType = 'warning',
+  actions,
+  iconClassName,
+  extraContent,
+}: {
+  title: string
+  description: React.ReactNode
+  iconType?: string
+  actions?: React.ReactNode
+  iconClassName?: string
+  extraContent?: React.ReactNode
+}) {
+  return (
+    <div className="pdf-error-state">
+      <div className="pdf-error-state-top-section">
+        <div
+          className={classNames(
+            'pdf-error-state-icon',
+            'pdf-error-state-warning-icon',
+            iconClassName
+          )}
+        >
+          <MaterialIcon type={iconType} />
+        </div>
+        <div className="pdf-error-state-text">
+          <p className="pdf-error-state-label">{title}</p>
+          <p className="pdf-error-state-description">{description}</p>
+        </div>
+        {actions}
+      </div>
+      {extraContent}
+    </div>
+  )
+}
+
+export const CheckLogsButton = () => {
+  const { t } = useTranslation()
+  const { openTab: openRailTab } = useRailContext()
+
+  return (
+    <OLButton
+      variant="secondary"
+      size="sm"
+      onClick={() => {
+        openRailTab('errors')
+      }}
+    >
+      {t('check_logs')}
+    </OLButton>
+  )
+}

+ 30 - 0
services/web/frontend/js/features/ide-redesign/components/pdf-preview/pdf-error-state/general-error-state.tsx

@@ -0,0 +1,30 @@
+import { useTranslation } from 'react-i18next'
+import ErrorState, { CheckLogsButton } from './error-state'
+import MaterialIcon from '@/shared/components/material-icon'
+
+export default function GeneralErrorState() {
+  const { t } = useTranslation()
+
+  return (
+    <ErrorState
+      title={t('pdf_couldnt_compile')}
+      description={t('we_are_unable_to_generate_the_pdf_at_this_time')}
+      actions={<CheckLogsButton />}
+      extraContent={
+        <div className="pdf-error-state-info-box">
+          <div className="pdf-error-state-info-box-title">
+            <MaterialIcon type="info" unfilled />
+            {t('why_might_this_happen')}
+          </div>
+          <div className="pdf-error-state-info-box-text">
+            <ul className="pdf-error-state-info-box-list">
+              <li>{t('there_is_an_unrecoverable_latex_error_check_logs')}</li>
+              <li>{t('the_document_environment_contains_no_content')}</li>
+              <li>{t('this_project_contains_a_file_called_output')}</li>
+            </ul>
+          </div>
+        </div>
+      }
+    />
+  )
+}

+ 139 - 0
services/web/frontend/js/features/ide-redesign/components/pdf-preview/pdf-error-state/pdf-error-state.tsx

@@ -0,0 +1,139 @@
+import { Trans, useTranslation } from 'react-i18next'
+import { usePdfPreviewContext } from '@/features/pdf-preview/components/pdf-preview-provider'
+import { useDetachCompileContext as useCompileContext } from '@/shared/context/detach-compile-context'
+import { useIsNewEditorEnabled } from '../../../utils/new-editor-utils'
+import ErrorState, { CheckLogsButton } from './error-state'
+import {
+  LongCompileTimeoutErrorState,
+  ShortCompileTimeoutErrorState,
+} from './compile-timeout-error-state'
+import GeneralErrorState from './general-error-state'
+
+// AvailableStates
+// - rendering-error-expected
+// - rendering-error
+// - clsi-maintenance
+// - clsi-unavailable
+// - too-recently-compiled
+// - terminated
+// - rate-limited
+// - compile-in-progress
+// - autocompile-disabled
+// - project-too-large
+// - timedout
+// - failure
+// - clear-cache
+// - pdf-viewer-loading-error
+// - validation-problems
+function PdfErrorState() {
+  const { loadingError } = usePdfPreviewContext()
+  // TODO ide-redesign-cleanup: rename showLogs to something else and check usages
+  const { hasShortCompileTimeout, error, showLogs } = useCompileContext()
+  const newEditor = useIsNewEditorEnabled()
+  const { t } = useTranslation()
+
+  if (!newEditor || (!loadingError && !showLogs)) {
+    return null
+  }
+
+  switch (error) {
+    case 'timedout': {
+      if (hasShortCompileTimeout) {
+        return <ShortCompileTimeoutErrorState />
+      } else {
+        return <LongCompileTimeoutErrorState />
+      }
+    }
+    case 'compile-in-progress':
+      return (
+        <ErrorState
+          title={t('pdf_compile_in_progress_error')}
+          description={t('pdf_compile_try_again')}
+        />
+      )
+    case 'clsi-maintenance':
+      return (
+        <ErrorState
+          title={t('server_error')}
+          description={t('clsi_maintenance')}
+          iconType="build"
+        />
+      )
+    case 'clsi-unavailable':
+      return (
+        <ErrorState
+          title={t('server_error')}
+          description={t('clsi_unavailable')}
+        />
+      )
+    case 'too-recently-compiled':
+      return (
+        <ErrorState
+          title={t('server_error')}
+          description={t('too_recently_compiled')}
+        />
+      )
+    case 'terminated':
+      return (
+        <ErrorState
+          title={t('terminated')}
+          description={t('compile_terminated_by_user')}
+          actions={<CheckLogsButton />}
+        />
+      )
+    case 'rate-limited':
+      return (
+        <ErrorState
+          title={t('pdf_compile_rate_limit_hit')}
+          description={t('project_flagged_too_many_compiles')}
+        />
+      )
+    case 'autocompile-disabled':
+      return (
+        <ErrorState
+          title={t('autocompile_disabled')}
+          description={t('autocompile_disabled_reason')}
+        />
+      )
+    case 'project-too-large':
+      return (
+        <ErrorState
+          title={t('project_too_large')}
+          description={t('project_too_much_editable_text')}
+        />
+      )
+    case 'clear-cache':
+      return (
+        <ErrorState
+          title={t('server_error')}
+          description={t('somthing_went_wrong_compiling')}
+        />
+      )
+    case 'pdf-viewer-loading-error':
+      return (
+        <ErrorState
+          title={t('pdf_rendering_error')}
+          description={
+            <Trans
+              i18nKey="something_went_wrong_loading_pdf_viewer"
+              components={[
+                <strong key="strong-" />,
+                // eslint-disable-next-line jsx-a11y/anchor-has-content
+                <a
+                  href="/learn/how-to/Resolving_access%2C_loading%2C_and_display_problems"
+                  target="_blank"
+                  key="troubleshooting-link"
+                />,
+                // eslint-disable-next-line jsx-a11y/anchor-has-content
+                <a key="contact-link" target="_blank" href="/contact" />,
+              ]}
+            />
+          }
+        />
+      )
+    default:
+      return <GeneralErrorState />
+  }
+}
+
+export default PdfErrorState

+ 1 - 1
services/web/frontend/js/features/pdf-preview/components/pdf-preview-pane.tsx

@@ -9,7 +9,7 @@ import { PdfPreviewMessages } from './pdf-preview-messages'
 import CompileTimeWarningUpgradePrompt from './compile-time-warning-upgrade-prompt'
 import { PdfPreviewProvider } from './pdf-preview-provider'
 import PdfPreviewHybridToolbarNew from '@/features/ide-redesign/components/pdf-preview/pdf-preview-hybrid-toolbar'
-import PdfErrorState from '@/features/ide-redesign/components/pdf-preview/pdf-error-state'
+import PdfErrorState from '@/features/ide-redesign/components/pdf-preview/pdf-error-state/pdf-error-state'
 import { useIsNewEditorEnabled } from '@/features/ide-redesign/utils/new-editor-utils'
 import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
 import PdfCodeCheckFailedBanner from '@/features/ide-redesign/components/pdf-preview/pdf-code-check-failed-banner'

+ 4 - 1
services/web/frontend/stories/pdf-error-state.stories.tsx

@@ -1,7 +1,7 @@
 import useFetchMock from './hooks/use-fetch-mock'
 import { mockCompile } from './fixtures/compile'
 import { ScopeDecorator, user } from './decorators/scope'
-import PdfErrorState from '@/features/ide-redesign/components/pdf-preview/pdf-error-state'
+import PdfErrorState from '@/features/ide-redesign/components/pdf-preview/pdf-error-state/pdf-error-state'
 import { useDetachCompileContext as useCompileContext } from '@/shared/context/detach-compile-context'
 import { useEffect } from 'react'
 import PdfPreview from '@/features/pdf-preview/components/pdf-preview'
@@ -12,13 +12,16 @@ export default {
 }
 
 const compileErrors = [
+  'autocompile-disabled',
   'autocompile-backoff',
   'clear-cache',
   'clsi-maintenance',
+  'clsi-unavailable',
   'compile-in-progress',
   'exited',
   'failure',
   'generic',
+  'pdf-viewer-loading-error',
   'project-too-large',
   'rate-limited',
   'success',