import { useTranslation } from 'react-i18next' import { memo, useCallback, useMemo, useState } from 'react' import { usePdfPreviewContext } from '@/features/pdf-preview/components/pdf-preview-provider' import StopOnFirstErrorPrompt from '@/features/pdf-preview/components/stop-on-first-error-prompt' import PdfPreviewError from '@/features/pdf-preview/components/pdf-preview-error' import PdfValidationIssue from '@/features/pdf-preview/components/pdf-validation-issue' import PdfLogsEntries from '@/features/pdf-preview/components/pdf-logs-entries' import PdfPreviewErrorBoundaryFallback from '@/features/pdf-preview/components/pdf-preview-error-boundary-fallback' import withErrorBoundary from '@/infrastructure/error-boundary' import { useDetachCompileContext as useCompileContext } from '@/shared/context/detach-compile-context' import { Nav, NavLink, TabContainer, TabContent } from 'react-bootstrap' import { LogEntry as LogEntryData } from '@/features/pdf-preview/util/types' import LogEntry from './log-entry' import TimeoutUpgradePromptNew from '@/features/pdf-preview/components/timeout-upgrade-prompt-new' import getMeta from '@/utils/meta' import PdfClearCacheButton from '@/features/pdf-preview/components/pdf-clear-cache-button' import PdfDownloadFilesButton from '@/features/pdf-preview/components/pdf-download-files-button' import RollingBuildSelectedReminder from './rolling-build-selected-reminder' import ErrorAssistantAiPaywallNotification from './error-assistant-ai-paywall-notification' type ErrorLogTab = { key: string label: string entries: LogEntryData[] | undefined } function ErrorLogs({ includeActionButtons, }: { includeActionButtons?: boolean }) { const { error, logEntries, rawLog, validationIssues, stoppedOnFirstError } = useCompileContext() const { compileTimeout } = getMeta('ol-compileSettings') const { t } = useTranslation() const tabs = useMemo(() => { return [ { key: 'all', label: t('all_logs'), entries: logEntries?.all, }, { key: 'errors', label: t('errors'), entries: logEntries?.errors }, { key: 'warnings', label: t('warnings'), entries: logEntries?.warnings }, { key: 'info', label: t('info'), entries: logEntries?.typesetting }, ] }, [logEntries, t]) const { loadingError } = usePdfPreviewContext() const [activeTab, setActiveTab] = useState('all') const changeTab = useCallback( (key: string | null) => { if (tabs.some(tab => tab.key === key)) { setActiveTab(key) } }, [tabs] ) const entries = useMemo(() => { return tabs.find(tab => tab.key === activeTab)?.entries || [] }, [activeTab, tabs]) const includeErrors = activeTab === 'all' || activeTab === 'errors' const includeWarnings = activeTab === 'all' || activeTab === 'warnings' return (
{stoppedOnFirstError && includeErrors && } {loadingError && ( )} {compileTimeout < 60 && error === 'timedout' ? ( ) : ( <>{error && } )} {includeErrors && validationIssues && Object.entries(validationIssues).map(([name, issue]) => ( ))} {entries && ( 0 } /> )} {rawLog && activeTab === 'all' && ( )} {includeActionButtons && (
)}
) } function formatErrorNumber(num: number | undefined) { if (num === undefined) { return undefined } if (num > 99) { return '99+' } return Math.floor(num).toString() } const TabHeader = ({ tab, active }: { tab: ErrorLogTab; active: boolean }) => { return ( {tab.label}
{/* TODO: it would be nice if this number included custom errors */} {formatErrorNumber(tab.entries?.length)}
) } export default withErrorBoundary(memo(ErrorLogs), () => ( ))