mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Add compile status indicator to new React-based errors UI.
GitOrigin-RevId: 545953e156d589a56ffd038bb7a40bba97770d06
This commit is contained in:
parent
9c7e9cf125
commit
876c292d22
12 changed files with 334 additions and 52 deletions
|
@ -5,16 +5,16 @@ div.full-size.pdf(ng-controller="PdfController")
|
||||||
isAutoCompileOn: autocompile_enabled,
|
isAutoCompileOn: autocompile_enabled,
|
||||||
isCompiling: pdf.compiling,
|
isCompiling: pdf.compiling,
|
||||||
isDraftModeOn: draft,
|
isDraftModeOn: draft,
|
||||||
isSyntaxCheckOn: stop_on_validation_error
|
isSyntaxCheckOn: stop_on_validation_error,
|
||||||
|
logEntries: pdf.logEntries ? pdf.logEntries : {}
|
||||||
}`
|
}`
|
||||||
log-entries="pdf.logEntries ? pdf.logEntries.all : []"
|
|
||||||
on-recompile="recompile"
|
on-recompile="recompile"
|
||||||
on-run-syntax-check-now="runSyntaxCheckNow"
|
on-run-syntax-check-now="runSyntaxCheckNow"
|
||||||
on-set-auto-compile="setAutoCompile"
|
on-set-auto-compile="setAutoCompile"
|
||||||
on-set-draft-mode="setDraftMode"
|
on-set-draft-mode="setDraftMode"
|
||||||
on-set-syntax-check="setSyntaxCheck"
|
on-set-syntax-check="setSyntaxCheck"
|
||||||
on-toggle-logs="toggleLogs"
|
on-toggle-logs="toggleLogs"
|
||||||
should-show-logs="shouldShowLogs"
|
show-logs="shouldShowLogs"
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
.toolbar.toolbar-pdf(ng-class="{ 'changes-to-autocompile': changesToAutoCompile && !autoCompileLintingError }")
|
.toolbar.toolbar-pdf(ng-class="{ 'changes-to-autocompile': changesToAutoCompile && !autoCompileLintingError }")
|
||||||
|
|
|
@ -21,5 +21,9 @@
|
||||||
"loading",
|
"loading",
|
||||||
"no_messages",
|
"no_messages",
|
||||||
"send_first_message",
|
"send_first_message",
|
||||||
"your_message"
|
"your_message",
|
||||||
|
"your_project_has_errors",
|
||||||
|
"view_warnings",
|
||||||
|
"view_logs",
|
||||||
|
"view_pdf"
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
import Icon from '../../../shared/components/icon'
|
||||||
|
|
||||||
function PreviewLogEntry({ file, line, message, content, raw, level }) {
|
function PreviewLogEntry({ file, line, message, content, raw, level }) {
|
||||||
const logEntryClasses = classNames('alert', {
|
const logEntryClasses = classNames('alert', {
|
||||||
|
@ -11,7 +12,7 @@ function PreviewLogEntry({ file, line, message, content, raw, level }) {
|
||||||
return (
|
return (
|
||||||
<div className={logEntryClasses}>
|
<div className={logEntryClasses}>
|
||||||
<span className="line-no">
|
<span className="line-no">
|
||||||
<i className="fa fa-link" aria-hidden="true" />
|
<Icon type="link" />
|
||||||
{file ? <span>{file}</span> : null}
|
{file ? <span>{file}</span> : null}
|
||||||
{line ? <span>, {line}</span> : null}
|
{line ? <span>, {line}</span> : null}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
import React from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import Icon from '../../../shared/components/icon'
|
||||||
|
|
||||||
|
function PreviewLogsToggleButton({
|
||||||
|
onToggle,
|
||||||
|
showLogs,
|
||||||
|
logsState: { nErrors, nWarnings }
|
||||||
|
}) {
|
||||||
|
const toggleButtonClasses = classNames('btn', 'btn-xs', 'btn-toggle-logs', {
|
||||||
|
'btn-danger': !showLogs && nErrors,
|
||||||
|
'btn-warning': !showLogs && !nErrors && nWarnings,
|
||||||
|
'btn-default': showLogs || (!nErrors && !nWarnings)
|
||||||
|
})
|
||||||
|
|
||||||
|
function handleOnClick(e) {
|
||||||
|
e.currentTarget.blur()
|
||||||
|
onToggle()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={toggleButtonClasses}
|
||||||
|
onClick={handleOnClick}
|
||||||
|
>
|
||||||
|
{showLogs ? (
|
||||||
|
<ViewPdfButton />
|
||||||
|
) : (
|
||||||
|
<CompilationResultIndicator nErrors={nErrors} nWarnings={nWarnings} />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CompilationResultIndicator({ nErrors, nWarnings }) {
|
||||||
|
if (nErrors) {
|
||||||
|
return <ErrorsCompilationResultIndicator nErrors={nErrors} />
|
||||||
|
} else if (nWarnings) {
|
||||||
|
return <WarningsCompilationResultIndicator nWarnings={nWarnings} />
|
||||||
|
} else {
|
||||||
|
return <ViewLogsButton />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ErrorsCompilationResultIndicator({ nErrors }) {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Icon type="file-text-o" />
|
||||||
|
<span className="btn-toggle-logs-label">
|
||||||
|
{`${t('your_project_has_errors')} (${nErrors > 9 ? '9+' : nErrors})`}
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function WarningsCompilationResultIndicator({ nWarnings }) {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Icon type="file-text-o" />
|
||||||
|
<span className="btn-toggle-logs-label">
|
||||||
|
{`${t('view_warnings')} (${nWarnings > 9 ? '9+' : nWarnings})`}
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ViewLogsButton() {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Icon type="file-text-o" />
|
||||||
|
<span className="btn-toggle-logs-label">{t('view_logs')}</span>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ViewPdfButton() {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Icon type="file-pdf-o" />
|
||||||
|
<span className="btn-toggle-logs-label">{t('view_pdf')}</span>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
PreviewLogsToggleButton.propTypes = {
|
||||||
|
onToggle: PropTypes.func.isRequired,
|
||||||
|
logsState: PropTypes.shape({
|
||||||
|
nErrors: PropTypes.number.isRequired,
|
||||||
|
nWarnings: PropTypes.number.isRequired,
|
||||||
|
nLogEntries: PropTypes.number.isRequired
|
||||||
|
}),
|
||||||
|
showLogs: PropTypes.bool.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorsCompilationResultIndicator.propTypes = {
|
||||||
|
nErrors: PropTypes.number.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
WarningsCompilationResultIndicator.propTypes = {
|
||||||
|
nWarnings: PropTypes.number.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PreviewLogsToggleButton
|
|
@ -5,19 +5,33 @@ import PreviewLogsPane from './preview-logs-pane'
|
||||||
|
|
||||||
function PreviewPane({
|
function PreviewPane({
|
||||||
compilerState,
|
compilerState,
|
||||||
logEntries,
|
|
||||||
onRecompile,
|
onRecompile,
|
||||||
onRunSyntaxCheckNow,
|
onRunSyntaxCheckNow,
|
||||||
onSetAutoCompile,
|
onSetAutoCompile,
|
||||||
onSetDraftMode,
|
onSetDraftMode,
|
||||||
onSetSyntaxCheck,
|
onSetSyntaxCheck,
|
||||||
onToggleLogs,
|
onToggleLogs,
|
||||||
shouldShowLogs
|
showLogs
|
||||||
}) {
|
}) {
|
||||||
|
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
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PreviewToolbar
|
<PreviewToolbar
|
||||||
compilerState={compilerState}
|
compilerState={compilerState}
|
||||||
|
logsState={{ nErrors, nWarnings, nLogEntries }}
|
||||||
|
showLogs={showLogs}
|
||||||
onRecompile={onRecompile}
|
onRecompile={onRecompile}
|
||||||
onRunSyntaxCheckNow={onRunSyntaxCheckNow}
|
onRunSyntaxCheckNow={onRunSyntaxCheckNow}
|
||||||
onSetAutoCompile={onSetAutoCompile}
|
onSetAutoCompile={onSetAutoCompile}
|
||||||
|
@ -25,7 +39,9 @@ function PreviewPane({
|
||||||
onSetSyntaxCheck={onSetSyntaxCheck}
|
onSetSyntaxCheck={onSetSyntaxCheck}
|
||||||
onToggleLogs={onToggleLogs}
|
onToggleLogs={onToggleLogs}
|
||||||
/>
|
/>
|
||||||
{shouldShowLogs ? <PreviewLogsPane logEntries={logEntries} /> : null}
|
{showLogs ? (
|
||||||
|
<PreviewLogsPane logEntries={compilerState.logEntries.all} />
|
||||||
|
) : null}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -35,16 +51,16 @@ PreviewPane.propTypes = {
|
||||||
isAutoCompileOn: PropTypes.bool.isRequired,
|
isAutoCompileOn: PropTypes.bool.isRequired,
|
||||||
isCompiling: PropTypes.bool.isRequired,
|
isCompiling: PropTypes.bool.isRequired,
|
||||||
isDraftModeOn: PropTypes.bool.isRequired,
|
isDraftModeOn: PropTypes.bool.isRequired,
|
||||||
isSyntaxCheckOn: PropTypes.bool.isRequired
|
isSyntaxCheckOn: PropTypes.bool.isRequired,
|
||||||
|
logEntries: PropTypes.object.isRequired
|
||||||
}),
|
}),
|
||||||
logEntries: PropTypes.array,
|
|
||||||
onRecompile: PropTypes.func.isRequired,
|
onRecompile: PropTypes.func.isRequired,
|
||||||
onRunSyntaxCheckNow: PropTypes.func.isRequired,
|
onRunSyntaxCheckNow: PropTypes.func.isRequired,
|
||||||
onSetAutoCompile: PropTypes.func.isRequired,
|
onSetAutoCompile: PropTypes.func.isRequired,
|
||||||
onSetDraftMode: PropTypes.func.isRequired,
|
onSetDraftMode: PropTypes.func.isRequired,
|
||||||
onSetSyntaxCheck: PropTypes.func.isRequired,
|
onSetSyntaxCheck: PropTypes.func.isRequired,
|
||||||
onToggleLogs: PropTypes.func.isRequired,
|
onToggleLogs: PropTypes.func.isRequired,
|
||||||
shouldShowLogs: PropTypes.bool.isRequired
|
showLogs: PropTypes.bool.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PreviewPane
|
export default PreviewPane
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import classNames from 'classnames'
|
|
||||||
import { Dropdown, MenuItem } from 'react-bootstrap'
|
import { Dropdown, MenuItem } from 'react-bootstrap'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import Icon from '../../../shared/components/icon'
|
||||||
|
|
||||||
function PreviewRecompileButton({
|
function PreviewRecompileButton({
|
||||||
compilerState: {
|
compilerState: {
|
||||||
|
@ -19,20 +19,6 @@ function PreviewRecompileButton({
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const iconClasses = {
|
|
||||||
recompile: classNames('fa', 'fa-refresh', {
|
|
||||||
'fa-spin': isCompiling
|
|
||||||
}),
|
|
||||||
autoCompileOn: classNames('fa', 'fa-fw', { 'fa-check': isAutoCompileOn }),
|
|
||||||
autoCompileOff: classNames('fa', 'fa-fw', { 'fa-check': !isAutoCompileOn }),
|
|
||||||
compileModeNormal: classNames('fa', 'fa-fw', {
|
|
||||||
'fa-check': !isDraftModeOn
|
|
||||||
}),
|
|
||||||
compileModeDraft: classNames('fa', 'fa-fw', { 'fa-check': isDraftModeOn }),
|
|
||||||
syntaxCheckOn: classNames('fa', 'fa-fw', { 'fa-check': isSyntaxCheckOn }),
|
|
||||||
syntaxCheckOff: classNames('fa', 'fa-fw', { 'fa-check': !isSyntaxCheckOn })
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleSelectAutoCompileOn() {
|
function handleSelectAutoCompileOn() {
|
||||||
onSetAutoCompile(true)
|
onSetAutoCompile(true)
|
||||||
}
|
}
|
||||||
|
@ -60,7 +46,7 @@ function PreviewRecompileButton({
|
||||||
return (
|
return (
|
||||||
<Dropdown id="pdf-recompile-dropdown" className="btn-recompile-group">
|
<Dropdown id="pdf-recompile-dropdown" className="btn-recompile-group">
|
||||||
<button className="btn btn-recompile" onClick={onRecompile}>
|
<button className="btn btn-recompile" onClick={onRecompile}>
|
||||||
<i className={iconClasses.recompile} aria-hidden="true" />
|
<Icon type="refresh" spin={isCompiling} />
|
||||||
{isCompiling ? (
|
{isCompiling ? (
|
||||||
<span className="btn-recompile-label">
|
<span className="btn-recompile-label">
|
||||||
{t('compiling')}
|
{t('compiling')}
|
||||||
|
@ -74,33 +60,33 @@ function PreviewRecompileButton({
|
||||||
<Dropdown.Menu>
|
<Dropdown.Menu>
|
||||||
<MenuItem header>{t('auto_compile')}</MenuItem>
|
<MenuItem header>{t('auto_compile')}</MenuItem>
|
||||||
<MenuItem onSelect={handleSelectAutoCompileOn}>
|
<MenuItem onSelect={handleSelectAutoCompileOn}>
|
||||||
<i className={iconClasses.autoCompileOn} aria-hidden="true" />
|
<Icon type={isAutoCompileOn ? 'check' : ''} modifier="fw" />
|
||||||
{t('on')}
|
{t('on')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem onSelect={handleSelectAutoCompileOff}>
|
<MenuItem onSelect={handleSelectAutoCompileOff}>
|
||||||
<i className={iconClasses.autoCompileOff} aria-hidden="true" />
|
<Icon type={!isAutoCompileOn ? 'check' : ''} modifier="fw" />
|
||||||
{t('off')}
|
{t('off')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem header>{t('compile_mode')}</MenuItem>
|
<MenuItem header>{t('compile_mode')}</MenuItem>
|
||||||
<MenuItem onSelect={handleSelectDraftModeOff}>
|
<MenuItem onSelect={handleSelectDraftModeOff}>
|
||||||
<i className={iconClasses.compileModeNormal} aria-hidden="true" />
|
<Icon type={!isDraftModeOn ? 'check' : ''} modifier="fw" />
|
||||||
{t('normal')}
|
{t('normal')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem onSelect={handleSelectDraftModeOn}>
|
<MenuItem onSelect={handleSelectDraftModeOn}>
|
||||||
<i className={iconClasses.compileModeDraft} aria-hidden="true" />
|
<Icon type={isDraftModeOn ? 'check' : ''} modifier="fw" />
|
||||||
{t('fast')} <span className="subdued">[draft]</span>
|
{t('fast')} <span className="subdued">[draft]</span>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem header>Syntax Checks</MenuItem>
|
<MenuItem header>Syntax Checks</MenuItem>
|
||||||
<MenuItem onSelect={handleSelectSyntaxCheckOn}>
|
<MenuItem onSelect={handleSelectSyntaxCheckOn}>
|
||||||
<i className={iconClasses.syntaxCheckOn} aria-hidden="true" />
|
<Icon type={isSyntaxCheckOn ? 'check' : ''} modifier="fw" />
|
||||||
{t('stop_on_validation_error')}
|
{t('stop_on_validation_error')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem onSelect={handleSelectSyntaxCheckOff}>
|
<MenuItem onSelect={handleSelectSyntaxCheckOff}>
|
||||||
<i className={iconClasses.syntaxCheckOff} aria-hidden="true" />
|
<Icon type={!isSyntaxCheckOn ? 'check' : ''} modifier="fw" />
|
||||||
{t('ignore_validation_errors')}
|
{t('ignore_validation_errors')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem onSelect={onRunSyntaxCheckNow}>
|
<MenuItem onSelect={onRunSyntaxCheckNow}>
|
||||||
<i className="fa fa-fw" aria-hidden="true" />
|
<Icon type="" modifier="fw" />
|
||||||
{t('run_syntax_check_now')}
|
{t('run_syntax_check_now')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Dropdown.Menu>
|
</Dropdown.Menu>
|
||||||
|
@ -113,7 +99,8 @@ PreviewRecompileButton.propTypes = {
|
||||||
isAutoCompileOn: PropTypes.bool.isRequired,
|
isAutoCompileOn: PropTypes.bool.isRequired,
|
||||||
isCompiling: PropTypes.bool.isRequired,
|
isCompiling: PropTypes.bool.isRequired,
|
||||||
isDraftModeOn: PropTypes.bool.isRequired,
|
isDraftModeOn: PropTypes.bool.isRequired,
|
||||||
isSyntaxCheckOn: PropTypes.bool.isRequired
|
isSyntaxCheckOn: PropTypes.bool.isRequired,
|
||||||
|
logEntries: PropTypes.object.isRequired
|
||||||
}),
|
}),
|
||||||
onRecompile: PropTypes.func.isRequired,
|
onRecompile: PropTypes.func.isRequired,
|
||||||
onRunSyntaxCheckNow: PropTypes.func.isRequired,
|
onRunSyntaxCheckNow: PropTypes.func.isRequired,
|
||||||
|
|
|
@ -1,29 +1,38 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import PreviewRecompileButton from './preview-recompile-button'
|
import PreviewRecompileButton from './preview-recompile-button'
|
||||||
|
import PreviewLogsToggleButton from './preview-logs-toggle-button'
|
||||||
|
|
||||||
function PreviewToolbar({
|
function PreviewToolbar({
|
||||||
compilerState,
|
compilerState,
|
||||||
|
logsState,
|
||||||
onRecompile,
|
onRecompile,
|
||||||
onRunSyntaxCheckNow,
|
onRunSyntaxCheckNow,
|
||||||
onSetAutoCompile,
|
onSetAutoCompile,
|
||||||
onSetDraftMode,
|
onSetDraftMode,
|
||||||
onSetSyntaxCheck,
|
onSetSyntaxCheck,
|
||||||
onToggleLogs
|
onToggleLogs,
|
||||||
|
showLogs
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="toolbar toolbar-pdf">
|
<div className="toolbar toolbar-pdf">
|
||||||
<PreviewRecompileButton
|
<div className="toolbar-pdf-left">
|
||||||
compilerState={compilerState}
|
<PreviewRecompileButton
|
||||||
onRecompile={onRecompile}
|
compilerState={compilerState}
|
||||||
onRunSyntaxCheckNow={onRunSyntaxCheckNow}
|
onRecompile={onRecompile}
|
||||||
onSetAutoCompile={onSetAutoCompile}
|
onRunSyntaxCheckNow={onRunSyntaxCheckNow}
|
||||||
onSetDraftMode={onSetDraftMode}
|
onSetAutoCompile={onSetAutoCompile}
|
||||||
onSetSyntaxCheck={onSetSyntaxCheck}
|
onSetDraftMode={onSetDraftMode}
|
||||||
/>
|
onSetSyntaxCheck={onSetSyntaxCheck}
|
||||||
<button className="btn btn-sm btn-secondary" onClick={onToggleLogs}>
|
/>
|
||||||
Toggle logs
|
</div>
|
||||||
</button>
|
<div className="toolbar-pdf-right">
|
||||||
|
<PreviewLogsToggleButton
|
||||||
|
logsState={logsState}
|
||||||
|
showLogs={showLogs}
|
||||||
|
onToggle={onToggleLogs}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -33,8 +42,15 @@ PreviewToolbar.propTypes = {
|
||||||
isAutoCompileOn: PropTypes.bool.isRequired,
|
isAutoCompileOn: PropTypes.bool.isRequired,
|
||||||
isCompiling: PropTypes.bool.isRequired,
|
isCompiling: PropTypes.bool.isRequired,
|
||||||
isDraftModeOn: PropTypes.bool.isRequired,
|
isDraftModeOn: PropTypes.bool.isRequired,
|
||||||
isSyntaxCheckOn: PropTypes.bool.isRequired
|
isSyntaxCheckOn: PropTypes.bool.isRequired,
|
||||||
|
logEntries: PropTypes.object.isRequired
|
||||||
}),
|
}),
|
||||||
|
logsState: PropTypes.shape({
|
||||||
|
nErrors: PropTypes.number.isRequired,
|
||||||
|
nWarnings: PropTypes.number.isRequired,
|
||||||
|
nLogEntries: PropTypes.number.isRequired
|
||||||
|
}),
|
||||||
|
showLogs: PropTypes.bool.isRequired,
|
||||||
onRecompile: PropTypes.func.isRequired,
|
onRecompile: PropTypes.func.isRequired,
|
||||||
onRunSyntaxCheckNow: PropTypes.func.isRequired,
|
onRunSyntaxCheckNow: PropTypes.func.isRequired,
|
||||||
onSetAutoCompile: PropTypes.func.isRequired,
|
onSetAutoCompile: PropTypes.func.isRequired,
|
||||||
|
|
|
@ -25,7 +25,7 @@ export default (PdfManager = class PdfManager {
|
||||||
failure: false, // PDF failed to compile
|
failure: false, // PDF failed to compile
|
||||||
compiling: false,
|
compiling: false,
|
||||||
uncompiled: true,
|
uncompiled: true,
|
||||||
logEntries: [],
|
logEntries: {},
|
||||||
logEntryAnnotations: {},
|
logEntryAnnotations: {},
|
||||||
rawLog: '',
|
rawLog: '',
|
||||||
view: null, // 'pdf' 'logs'
|
view: null, // 'pdf' 'logs'
|
||||||
|
|
|
@ -271,7 +271,7 @@ App.controller('PdfController', function(
|
||||||
}
|
}
|
||||||
// if the previous run was a check, clear the error logs
|
// if the previous run was a check, clear the error logs
|
||||||
if ($scope.check) {
|
if ($scope.check) {
|
||||||
$scope.pdf.logEntries = []
|
$scope.pdf.logEntries = {}
|
||||||
}
|
}
|
||||||
// keep track of whether this is a compile or check
|
// keep track of whether this is a compile or check
|
||||||
$scope.check = !!options.check
|
$scope.check = !!options.check
|
||||||
|
@ -622,7 +622,7 @@ App.controller('PdfController', function(
|
||||||
|
|
||||||
// output the results
|
// output the results
|
||||||
function handleError() {
|
function handleError() {
|
||||||
$scope.pdf.logEntries = []
|
$scope.pdf.logEntries = {}
|
||||||
$scope.pdf.rawLog = ''
|
$scope.pdf.rawLog = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,28 @@
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toolbar-pdf-left,
|
||||||
|
.toolbar-pdf-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
align-self: stretch;
|
||||||
|
flex: 1 1 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-pdf-right {
|
||||||
|
flex: 1 0 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-toggle-logs {
|
||||||
|
&:focus,
|
||||||
|
&:active:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.btn-toggle-logs-label {
|
||||||
|
padding-left: @line-height-computed / 4;
|
||||||
|
}
|
||||||
|
|
||||||
.pdf {
|
.pdf {
|
||||||
background-color: @pdf-bg;
|
background-color: @pdf-bg;
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,7 +207,7 @@
|
||||||
@btn-info-border: transparent;
|
@btn-info-border: transparent;
|
||||||
|
|
||||||
@btn-warning-color: #fff;
|
@btn-warning-color: #fff;
|
||||||
@btn-warning-bg: @ol-red;
|
@btn-warning-bg: @orange;
|
||||||
@btn-warning-border: transparent;
|
@btn-warning-border: transparent;
|
||||||
|
|
||||||
@btn-danger-color: #fff;
|
@btn-danger-color: #fff;
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { screen, render } from '@testing-library/react'
|
||||||
|
|
||||||
|
import PreviewLogsToggleButton from '../../../../../frontend/js/features/preview/components/preview-logs-toggle-button'
|
||||||
|
|
||||||
|
describe('<PreviewLogsToggleButton />', function() {
|
||||||
|
describe('basic toggle functionality', function() {
|
||||||
|
const logsState = {
|
||||||
|
nErrors: 0,
|
||||||
|
nWarnings: 0,
|
||||||
|
nLogEntries: 0
|
||||||
|
}
|
||||||
|
const onToggleLogs = () => {}
|
||||||
|
it('should render a view logs button when previewing the PDF', function() {
|
||||||
|
const showLogs = false
|
||||||
|
render(
|
||||||
|
<PreviewLogsToggleButton
|
||||||
|
logsState={logsState}
|
||||||
|
showLogs={showLogs}
|
||||||
|
onToggle={onToggleLogs}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
screen.getByRole('button', { name: 'View logs' })
|
||||||
|
})
|
||||||
|
it('should render a view PDF button when viewing logs', function() {
|
||||||
|
const showLogs = true
|
||||||
|
render(
|
||||||
|
<PreviewLogsToggleButton
|
||||||
|
logsState={logsState}
|
||||||
|
showLogs={showLogs}
|
||||||
|
onToggle={onToggleLogs}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
screen.getByRole('button', { name: 'View PDF' })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('compile status indicator', function() {
|
||||||
|
const showLogs = false
|
||||||
|
const onToggleLogs = () => {}
|
||||||
|
it('should render a view logs button by default', function() {
|
||||||
|
const logsState = {
|
||||||
|
nErrors: 0,
|
||||||
|
nWarnings: 0,
|
||||||
|
nLogEntries: 0
|
||||||
|
}
|
||||||
|
render(
|
||||||
|
<PreviewLogsToggleButton
|
||||||
|
logsState={logsState}
|
||||||
|
showLogs={showLogs}
|
||||||
|
onToggle={onToggleLogs}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
screen.getByRole('button', { name: 'View logs' })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render an error status message when there are errors', function() {
|
||||||
|
const logsState = {
|
||||||
|
nErrors: 1,
|
||||||
|
nWarnings: 0,
|
||||||
|
nLogEntries: 0
|
||||||
|
}
|
||||||
|
render(
|
||||||
|
<PreviewLogsToggleButton
|
||||||
|
logsState={logsState}
|
||||||
|
showLogs={showLogs}
|
||||||
|
onToggle={onToggleLogs}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
screen.getByRole('button', {
|
||||||
|
name: `Your project has errors (${logsState.nErrors})`
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render an error status message when there are both errors and warnings', function() {
|
||||||
|
const logsState = {
|
||||||
|
nErrors: 1,
|
||||||
|
nWarnings: 1,
|
||||||
|
nLogEntries: 0
|
||||||
|
}
|
||||||
|
render(
|
||||||
|
<PreviewLogsToggleButton
|
||||||
|
logsState={logsState}
|
||||||
|
showLogs={showLogs}
|
||||||
|
onToggle={onToggleLogs}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
screen.getByRole('button', {
|
||||||
|
name: `Your project has errors (${logsState.nErrors})`
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render a warning status message when there are warnings but no errors', function() {
|
||||||
|
const logsState = {
|
||||||
|
nErrors: 0,
|
||||||
|
nWarnings: 1,
|
||||||
|
nLogEntries: 0
|
||||||
|
}
|
||||||
|
render(
|
||||||
|
<PreviewLogsToggleButton
|
||||||
|
logsState={logsState}
|
||||||
|
showLogs={showLogs}
|
||||||
|
onToggle={onToggleLogs}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
screen.getByRole('button', {
|
||||||
|
name: `View warnings (${logsState.nWarnings})`
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render 9+ errors when there are more than nine errors', function() {
|
||||||
|
const logsState = {
|
||||||
|
nErrors: 10,
|
||||||
|
nWarnings: 0,
|
||||||
|
nLogEntries: 0
|
||||||
|
}
|
||||||
|
render(
|
||||||
|
<PreviewLogsToggleButton
|
||||||
|
logsState={logsState}
|
||||||
|
showLogs={showLogs}
|
||||||
|
onToggle={onToggleLogs}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
screen.getByRole('button', { name: `Your project has errors (9+)` })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in a new issue