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,
|
||||
isCompiling: pdf.compiling,
|
||||
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-run-syntax-check-now="runSyntaxCheckNow"
|
||||
on-set-auto-compile="setAutoCompile"
|
||||
on-set-draft-mode="setDraftMode"
|
||||
on-set-syntax-check="setSyntaxCheck"
|
||||
on-toggle-logs="toggleLogs"
|
||||
should-show-logs="shouldShowLogs"
|
||||
show-logs="shouldShowLogs"
|
||||
)
|
||||
else
|
||||
.toolbar.toolbar-pdf(ng-class="{ 'changes-to-autocompile': changesToAutoCompile && !autoCompileLintingError }")
|
||||
|
|
|
@ -21,5 +21,9 @@
|
|||
"loading",
|
||||
"no_messages",
|
||||
"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 PropTypes from 'prop-types'
|
||||
import classNames from 'classnames'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
|
||||
function PreviewLogEntry({ file, line, message, content, raw, level }) {
|
||||
const logEntryClasses = classNames('alert', {
|
||||
|
@ -11,7 +12,7 @@ function PreviewLogEntry({ file, line, message, content, raw, level }) {
|
|||
return (
|
||||
<div className={logEntryClasses}>
|
||||
<span className="line-no">
|
||||
<i className="fa fa-link" aria-hidden="true" />
|
||||
<Icon type="link" />
|
||||
{file ? <span>{file}</span> : null}
|
||||
{line ? <span>, {line}</span> : null}
|
||||
</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({
|
||||
compilerState,
|
||||
logEntries,
|
||||
onRecompile,
|
||||
onRunSyntaxCheckNow,
|
||||
onSetAutoCompile,
|
||||
onSetDraftMode,
|
||||
onSetSyntaxCheck,
|
||||
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 (
|
||||
<>
|
||||
<PreviewToolbar
|
||||
compilerState={compilerState}
|
||||
logsState={{ nErrors, nWarnings, nLogEntries }}
|
||||
showLogs={showLogs}
|
||||
onRecompile={onRecompile}
|
||||
onRunSyntaxCheckNow={onRunSyntaxCheckNow}
|
||||
onSetAutoCompile={onSetAutoCompile}
|
||||
|
@ -25,7 +39,9 @@ function PreviewPane({
|
|||
onSetSyntaxCheck={onSetSyntaxCheck}
|
||||
onToggleLogs={onToggleLogs}
|
||||
/>
|
||||
{shouldShowLogs ? <PreviewLogsPane logEntries={logEntries} /> : null}
|
||||
{showLogs ? (
|
||||
<PreviewLogsPane logEntries={compilerState.logEntries.all} />
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -35,16 +51,16 @@ PreviewPane.propTypes = {
|
|||
isAutoCompileOn: PropTypes.bool.isRequired,
|
||||
isCompiling: 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,
|
||||
onRunSyntaxCheckNow: PropTypes.func.isRequired,
|
||||
onSetAutoCompile: PropTypes.func.isRequired,
|
||||
onSetDraftMode: PropTypes.func.isRequired,
|
||||
onSetSyntaxCheck: PropTypes.func.isRequired,
|
||||
onToggleLogs: PropTypes.func.isRequired,
|
||||
shouldShowLogs: PropTypes.bool.isRequired
|
||||
showLogs: PropTypes.bool.isRequired
|
||||
}
|
||||
|
||||
export default PreviewPane
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import classNames from 'classnames'
|
||||
import { Dropdown, MenuItem } from 'react-bootstrap'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
|
||||
function PreviewRecompileButton({
|
||||
compilerState: {
|
||||
|
@ -19,20 +19,6 @@ function PreviewRecompileButton({
|
|||
}) {
|
||||
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() {
|
||||
onSetAutoCompile(true)
|
||||
}
|
||||
|
@ -60,7 +46,7 @@ function PreviewRecompileButton({
|
|||
return (
|
||||
<Dropdown id="pdf-recompile-dropdown" className="btn-recompile-group">
|
||||
<button className="btn btn-recompile" onClick={onRecompile}>
|
||||
<i className={iconClasses.recompile} aria-hidden="true" />
|
||||
<Icon type="refresh" spin={isCompiling} />
|
||||
{isCompiling ? (
|
||||
<span className="btn-recompile-label">
|
||||
{t('compiling')}
|
||||
|
@ -74,33 +60,33 @@ function PreviewRecompileButton({
|
|||
<Dropdown.Menu>
|
||||
<MenuItem header>{t('auto_compile')}</MenuItem>
|
||||
<MenuItem onSelect={handleSelectAutoCompileOn}>
|
||||
<i className={iconClasses.autoCompileOn} aria-hidden="true" />
|
||||
<Icon type={isAutoCompileOn ? 'check' : ''} modifier="fw" />
|
||||
{t('on')}
|
||||
</MenuItem>
|
||||
<MenuItem onSelect={handleSelectAutoCompileOff}>
|
||||
<i className={iconClasses.autoCompileOff} aria-hidden="true" />
|
||||
<Icon type={!isAutoCompileOn ? 'check' : ''} modifier="fw" />
|
||||
{t('off')}
|
||||
</MenuItem>
|
||||
<MenuItem header>{t('compile_mode')}</MenuItem>
|
||||
<MenuItem onSelect={handleSelectDraftModeOff}>
|
||||
<i className={iconClasses.compileModeNormal} aria-hidden="true" />
|
||||
<Icon type={!isDraftModeOn ? 'check' : ''} modifier="fw" />
|
||||
{t('normal')}
|
||||
</MenuItem>
|
||||
<MenuItem onSelect={handleSelectDraftModeOn}>
|
||||
<i className={iconClasses.compileModeDraft} aria-hidden="true" />
|
||||
<Icon type={isDraftModeOn ? 'check' : ''} modifier="fw" />
|
||||
{t('fast')} <span className="subdued">[draft]</span>
|
||||
</MenuItem>
|
||||
<MenuItem header>Syntax Checks</MenuItem>
|
||||
<MenuItem onSelect={handleSelectSyntaxCheckOn}>
|
||||
<i className={iconClasses.syntaxCheckOn} aria-hidden="true" />
|
||||
<Icon type={isSyntaxCheckOn ? 'check' : ''} modifier="fw" />
|
||||
{t('stop_on_validation_error')}
|
||||
</MenuItem>
|
||||
<MenuItem onSelect={handleSelectSyntaxCheckOff}>
|
||||
<i className={iconClasses.syntaxCheckOff} aria-hidden="true" />
|
||||
<Icon type={!isSyntaxCheckOn ? 'check' : ''} modifier="fw" />
|
||||
{t('ignore_validation_errors')}
|
||||
</MenuItem>
|
||||
<MenuItem onSelect={onRunSyntaxCheckNow}>
|
||||
<i className="fa fa-fw" aria-hidden="true" />
|
||||
<Icon type="" modifier="fw" />
|
||||
{t('run_syntax_check_now')}
|
||||
</MenuItem>
|
||||
</Dropdown.Menu>
|
||||
|
@ -113,7 +99,8 @@ PreviewRecompileButton.propTypes = {
|
|||
isAutoCompileOn: PropTypes.bool.isRequired,
|
||||
isCompiling: PropTypes.bool.isRequired,
|
||||
isDraftModeOn: PropTypes.bool.isRequired,
|
||||
isSyntaxCheckOn: PropTypes.bool.isRequired
|
||||
isSyntaxCheckOn: PropTypes.bool.isRequired,
|
||||
logEntries: PropTypes.object.isRequired
|
||||
}),
|
||||
onRecompile: PropTypes.func.isRequired,
|
||||
onRunSyntaxCheckNow: PropTypes.func.isRequired,
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import PreviewRecompileButton from './preview-recompile-button'
|
||||
import PreviewLogsToggleButton from './preview-logs-toggle-button'
|
||||
|
||||
function PreviewToolbar({
|
||||
compilerState,
|
||||
logsState,
|
||||
onRecompile,
|
||||
onRunSyntaxCheckNow,
|
||||
onSetAutoCompile,
|
||||
onSetDraftMode,
|
||||
onSetSyntaxCheck,
|
||||
onToggleLogs
|
||||
onToggleLogs,
|
||||
showLogs
|
||||
}) {
|
||||
return (
|
||||
<div className="toolbar toolbar-pdf">
|
||||
<div className="toolbar-pdf-left">
|
||||
<PreviewRecompileButton
|
||||
compilerState={compilerState}
|
||||
onRecompile={onRecompile}
|
||||
|
@ -21,9 +25,14 @@ function PreviewToolbar({
|
|||
onSetDraftMode={onSetDraftMode}
|
||||
onSetSyntaxCheck={onSetSyntaxCheck}
|
||||
/>
|
||||
<button className="btn btn-sm btn-secondary" onClick={onToggleLogs}>
|
||||
Toggle logs
|
||||
</button>
|
||||
</div>
|
||||
<div className="toolbar-pdf-right">
|
||||
<PreviewLogsToggleButton
|
||||
logsState={logsState}
|
||||
showLogs={showLogs}
|
||||
onToggle={onToggleLogs}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -33,8 +42,15 @@ PreviewToolbar.propTypes = {
|
|||
isAutoCompileOn: PropTypes.bool.isRequired,
|
||||
isCompiling: 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,
|
||||
onRunSyntaxCheckNow: PropTypes.func.isRequired,
|
||||
onSetAutoCompile: PropTypes.func.isRequired,
|
||||
|
|
|
@ -25,7 +25,7 @@ export default (PdfManager = class PdfManager {
|
|||
failure: false, // PDF failed to compile
|
||||
compiling: false,
|
||||
uncompiled: true,
|
||||
logEntries: [],
|
||||
logEntries: {},
|
||||
logEntryAnnotations: {},
|
||||
rawLog: '',
|
||||
view: null, // 'pdf' 'logs'
|
||||
|
|
|
@ -271,7 +271,7 @@ App.controller('PdfController', function(
|
|||
}
|
||||
// if the previous run was a check, clear the error logs
|
||||
if ($scope.check) {
|
||||
$scope.pdf.logEntries = []
|
||||
$scope.pdf.logEntries = {}
|
||||
}
|
||||
// keep track of whether this is a compile or check
|
||||
$scope.check = !!options.check
|
||||
|
@ -622,7 +622,7 @@ App.controller('PdfController', function(
|
|||
|
||||
// output the results
|
||||
function handleError() {
|
||||
$scope.pdf.logEntries = []
|
||||
$scope.pdf.logEntries = {}
|
||||
$scope.pdf.rawLog = ''
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,28 @@
|
|||
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 {
|
||||
background-color: @pdf-bg;
|
||||
}
|
||||
|
|
|
@ -207,7 +207,7 @@
|
|||
@btn-info-border: transparent;
|
||||
|
||||
@btn-warning-color: #fff;
|
||||
@btn-warning-bg: @ol-red;
|
||||
@btn-warning-bg: @orange;
|
||||
@btn-warning-border: transparent;
|
||||
|
||||
@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