import PropTypes from 'prop-types' import { useTranslation } from 'react-i18next' import { Dropdown } from 'react-bootstrap' import PreviewLogsPaneEntry from './preview-logs-pane-entry' import PreviewLogsPaneMaxEntries from './preview-logs-pane-max-entries' import PreviewValidationIssue from './preview-validation-issue' import PreviewDownloadFileList from './preview-download-file-list' import PreviewError from './preview-error' import Icon from '../../../shared/components/icon' import usePersistedState from '../../../shared/hooks/use-persisted-state' import ControlledDropdown from '../../../shared/components/controlled-dropdown' const LOG_PREVIEW_LIMIT = 100 function PreviewLogsPane({ logEntries = { all: [], errors: [], warnings: [], typesetting: [] }, rawLog = '', validationIssues = {}, errors = {}, outputFiles = [], isClearingCache, isCompiling = false, autoCompileHasLintingError = false, variantWithFirstErrorPopup, onLogEntryLocationClick, onClearCache, }) { const { t } = useTranslation() const { all: allCompilerIssues = [], errors: compilerErrors = [], warnings: compilerWarnings = [], typesetting: compilerTypesettingIssues = [], } = logEntries const allLogEntries = [ ...compilerErrors, ...compilerWarnings, ...compilerTypesettingIssues, ] const actionsUI = (
) const rawLogUI = ( ) return (
{autoCompileHasLintingError ? : null} {errors ? : null} {validationIssues ? ( ) : null} {allCompilerIssues.length > 0 ? ( ) : null} {rawLog && rawLog !== '' ? rawLogUI : null} {actionsUI}
) } const PreviewErrors = ({ errors }) => { const nowTS = Date.now() return Object.entries(errors).map(([name, exists], index) => { return exists && }) } const PreviewValidationIssues = ({ validationIssues }) => { const nowTS = Date.now() return Object.keys(validationIssues).map((name, index) => ( )) } const PreviewLogEntries = ({ logEntries, onLogEntryLocationClick }) => { const { t } = useTranslation() const nowTS = Date.now() const totalLogEntries = logEntries.length if (totalLogEntries > LOG_PREVIEW_LIMIT) { logEntries = logEntries.slice(0, 100) } logEntries = logEntries.map((logEntry, index) => ( )) if (totalLogEntries > LOG_PREVIEW_LIMIT) { // Prepend log limit exceeded message to logs array logEntries = [ , ].concat(logEntries) } return logEntries } function AutoCompileLintingErrorEntry() { const { t } = useTranslation() return (

{t('code_check_failed_explanation')}

) } // exported to be used by pdf-viewer during React migration export function LogsPaneInfoNotice({ variantWithFirstErrorPopup }) { const { t } = useTranslation() const [dismissedInfoNotice, setDismissedInfoNotice] = usePersistedState( `logs_pane.dismissed_info_notice`, false ) const surveyLink = variantWithFirstErrorPopup ? 'https://forms.gle/AUbDDRvroQ7KFwHR9' : 'https://forms.gle/bRxevtGzBHRk8BKw8' function handleDismissButtonClick() { setDismissedInfoNotice(true) } return dismissedInfoNotice ? null : (

{t('logs_pane_info_message')}

{t('give_feedback')}
) } PreviewErrors.propTypes = { errors: PropTypes.object.isRequired, } PreviewValidationIssues.propTypes = { validationIssues: PropTypes.object.isRequired, } PreviewLogEntries.propTypes = { logEntries: PropTypes.array.isRequired, onLogEntryLocationClick: PropTypes.func.isRequired, } LogsPaneInfoNotice.propTypes = { variantWithFirstErrorPopup: PropTypes.bool, } PreviewLogsPane.propTypes = { logEntries: PropTypes.shape({ all: PropTypes.array, errors: PropTypes.array, warning: PropTypes.array, typesetting: PropTypes.array, }), autoCompileHasLintingError: PropTypes.bool, rawLog: PropTypes.string, outputFiles: PropTypes.array, isClearingCache: PropTypes.bool, isCompiling: PropTypes.bool, variantWithFirstErrorPopup: PropTypes.bool, onLogEntryLocationClick: PropTypes.func.isRequired, onClearCache: PropTypes.func.isRequired, validationIssues: PropTypes.object, errors: PropTypes.object, } export default PreviewLogsPane