overleaf/services/web/frontend/js/features/preview/components/preview-pane.js
Paulo Jorge Reis 4e74fb2694 Log pane improvements (#3418)
* Ordering of log entries in the new errors UI

* Don't show the expand-collapse widget when not needed; smaller font size in the raw log output

* Expose log actions in the log pane.

* Use "This project" instead of "Your project" in the new errors UI

* Better handling of long log messages; left-ellipsize the file/line number button

* Make log location more button-like; add tooltip when needed.

* Add a PDF expand button to the toolbar.

* Add a stop compilation button to the new compile UI

* Use aria-label for button accessible text; improve handling of long filenames in the log location button

* Set max-height correctly for the logs pane dropdown

* Avoid changing raw logs sizing when expanded and collapsed

* Add comment on the solution for right-to-left text and ellipsis

* Improve logs pane actions

GitOrigin-RevId: 4098d77a9ee6d333644906876b9ff27035b79319
2020-12-03 03:04:28 +00:00

176 lines
5.5 KiB
JavaScript

import React, { useState } from 'react'
import PropTypes from 'prop-types'
import PreviewToolbar from './preview-toolbar'
import PreviewLogsPane from './preview-logs-pane'
import PreviewFirstErrorPopUp from './preview-first-error-pop-up'
import { useTranslation } from 'react-i18next'
function PreviewPane({
compilerState,
onClearCache,
onRecompile,
onRecompileFromScratch,
onRunSyntaxCheckNow,
onSetAutoCompile,
onSetDraftMode,
onSetSyntaxCheck,
onToggleLogs,
onSetFullLayout,
onSetSplitLayout,
onStopCompilation,
outputFiles,
pdfDownloadUrl,
onLogEntryLocationClick,
showLogs,
splitLayout
}) {
const { t } = useTranslation()
const [lastCompileTimestamp, setLastCompileTimestamp] = useState(
compilerState.lastCompileTimestamp
)
const [seenLogsForCurrentCompile, setSeenLogsForCurrentCompile] = useState(
false
)
const [dismissedFirstErrorPopUp, setDismissedFirstErrorPopUp] = useState(
false
)
if (lastCompileTimestamp < compilerState.lastCompileTimestamp) {
setLastCompileTimestamp(compilerState.lastCompileTimestamp)
setSeenLogsForCurrentCompile(false)
}
if (showLogs && !seenLogsForCurrentCompile) {
setSeenLogsForCurrentCompile(true)
}
const nErrors =
compilerState.logEntries && compilerState.logEntries.errors
? compilerState.logEntries.errors.length
: 0
const nWarnings =
compilerState.logEntries && compilerState.logEntries.warnings
? compilerState.logEntries.warnings.length
: 0
const nLogEntries =
compilerState.logEntries && compilerState.logEntries.all
? compilerState.logEntries.all.length
: 0
const hasCLSIErrors =
compilerState.errors &&
Object.keys(compilerState.errors).length > 0 &&
compilerState.compileFailed &&
!compilerState.isCompiling
const hasValidationIssues =
compilerState.validationIssues &&
Object.keys(compilerState.validationIssues).length > 0 &&
compilerState.compileFailed &&
!compilerState.isCompiling
const showFirstErrorPopUp =
nErrors > 0 &&
!seenLogsForCurrentCompile &&
!dismissedFirstErrorPopUp &&
!compilerState.isCompiling
function handleFirstErrorPopUpClose() {
setDismissedFirstErrorPopUp(true)
}
return (
<>
<PreviewToolbar
compilerState={compilerState}
logsState={{ nErrors, nWarnings, nLogEntries }}
showLogs={showLogs}
onRecompile={onRecompile}
onRecompileFromScratch={onRecompileFromScratch}
onRunSyntaxCheckNow={onRunSyntaxCheckNow}
onSetAutoCompile={onSetAutoCompile}
onSetDraftMode={onSetDraftMode}
onSetSyntaxCheck={onSetSyntaxCheck}
onToggleLogs={onToggleLogs}
onSetSplitLayout={onSetSplitLayout}
onSetFullLayout={onSetFullLayout}
onStopCompilation={onStopCompilation}
outputFiles={outputFiles}
pdfDownloadUrl={pdfDownloadUrl}
splitLayout={splitLayout}
/>
<span aria-live="polite" className="sr-only">
{hasCLSIErrors ? t('compile_error_description') : ''}
</span>
<span aria-live="polite" className="sr-only">
{hasValidationIssues ? t('validation_issue_description') : ''}
</span>
<span aria-live="polite" className="sr-only">
{nErrors && !compilerState.isCompiling
? t('n_errors', { count: nErrors })
: ''}
</span>
<span aria-live="polite" className="sr-only">
{nWarnings && !compilerState.isCompiling
? t('n_warnings', { count: nWarnings })
: ''}
</span>
{showFirstErrorPopUp ? (
<PreviewFirstErrorPopUp
logEntry={compilerState.logEntries.errors[0]}
onGoToErrorLocation={onLogEntryLocationClick}
onViewLogs={onToggleLogs}
onClose={handleFirstErrorPopUpClose}
/>
) : null}
{showLogs ? (
<PreviewLogsPane
logEntries={compilerState.logEntries}
rawLog={compilerState.rawLog}
validationIssues={compilerState.validationIssues}
errors={compilerState.errors}
outputFiles={outputFiles}
onLogEntryLocationClick={onLogEntryLocationClick}
isClearingCache={compilerState.isClearingCache}
isCompiling={compilerState.isCompiling}
onClearCache={onClearCache}
/>
) : null}
</>
)
}
PreviewPane.propTypes = {
compilerState: PropTypes.shape({
isAutoCompileOn: PropTypes.bool.isRequired,
isCompiling: PropTypes.bool.isRequired,
isDraftModeOn: PropTypes.bool.isRequired,
isSyntaxCheckOn: PropTypes.bool.isRequired,
isClearingCache: PropTypes.bool.isRequired,
lastCompileTimestamp: PropTypes.number,
logEntries: PropTypes.object,
validationIssues: PropTypes.object,
errors: PropTypes.object,
rawLog: PropTypes.string,
compileFailed: PropTypes.bool
}),
onClearCache: PropTypes.func.isRequired,
onLogEntryLocationClick: PropTypes.func.isRequired,
onRecompile: PropTypes.func.isRequired,
onRecompileFromScratch: PropTypes.func.isRequired,
onRunSyntaxCheckNow: PropTypes.func.isRequired,
onSetAutoCompile: PropTypes.func.isRequired,
onSetDraftMode: PropTypes.func.isRequired,
onSetSyntaxCheck: PropTypes.func.isRequired,
onSetSplitLayout: PropTypes.func.isRequired,
onSetFullLayout: PropTypes.func.isRequired,
onStopCompilation: PropTypes.func.isRequired,
onToggleLogs: PropTypes.func.isRequired,
outputFiles: PropTypes.array,
pdfDownloadUrl: PropTypes.string,
showLogs: PropTypes.bool.isRequired,
splitLayout: PropTypes.bool.isRequired
}
export default PreviewPane