Merge pull request #3175 from overleaf/pr-spike-new-logs-errors-ui

Spike new logs errors ui

GitOrigin-RevId: b4c598bc03d8aa8e5a438ac5633e18dadd82dc74
This commit is contained in:
Simon Detheridge
2020-09-28 11:51:15 +01:00
committed by Copybot
parent ec0240395f
commit 315987dc5a
11 changed files with 564 additions and 217 deletions
@@ -841,7 +841,8 @@ const ProjectController = {
showSupport: Features.hasFeature('support'),
gaOptimize: enableOptimize,
customOptimizeEvent: true,
experimentId: Settings.experimentId
experimentId: Settings.experimentId,
showNewLogsUI: req.query && req.query.new_logs_ui === 'true'
})
timer.done()
}
+229 -211
View File
@@ -1,224 +1,242 @@
div.full-size.pdf(ng-controller="PdfController")
.toolbar.toolbar-pdf(ng-class="{ 'changes-to-autocompile': changesToAutoCompile && !autoCompileLintingError }")
.btn-group.btn-recompile-group#recompile(
dropdown,
tooltip-html="'"+translate('recompile_pdf')+" <span class=\"keyboard-shortcut\">({{modifierKey}} + Enter)</span>'"
tooltip-class="keyboard-tooltip"
tooltip-popup-delay="500"
tooltip-append-to-body="true"
tooltip-placement="bottom"
if showNewLogsUI
preview-pane(
compiler-state=`{
isAutoCompileOn: autocompile_enabled,
isCompiling: pdf.compiling,
isDraftModeOn: draft,
isSyntaxCheckOn: stop_on_validation_error
}`
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"
)
a.btn.btn-recompile(
href,
ng-disabled="pdf.compiling",
ng-click="recompile()"
)
i.fa.fa-refresh(
ng-class="{'fa-spin': pdf.compiling }"
)
| &nbsp;&nbsp;
span(ng-show="!pdf.compiling") #{translate("recompile")}
span(ng-show="pdf.compiling") #{translate("compiling")}…
a.btn.btn-recompile.dropdown-toggle(
href,
ng-disabled="pdf.compiling",
dropdown-toggle
)
span.caret
ul.dropdown-menu.dropdown-menu-left
li.dropdown-header #{translate("auto_compile")}
li
a(href, ng-click="autocompile_enabled = true")
i.fa.fa-fw(ng-class="{'fa-check': autocompile_enabled}")
| &nbsp;#{translate('on')}
li
a(href, ng-click="autocompile_enabled = false")
i.fa.fa-fw(ng-class="{'fa-check': !autocompile_enabled}")
| &nbsp;#{translate('off')}
li.dropdown-header #{translate("compile_mode")}
li
a(href, ng-click="draft = false")
i.fa.fa-fw(ng-class="{'fa-check': !draft}")
| &nbsp;#{translate("normal")}
li
a(href, ng-click="draft = true")
i.fa.fa-fw(ng-class="{'fa-check': draft}")
| &nbsp;#{translate("fast")}&nbsp;
span.subdued [draft]
li.dropdown-header #{translate("compile_time_checks")}
li
a(href, ng-click="stop_on_validation_error = true")
i.fa.fa-fw(ng-class="{'fa-check': stop_on_validation_error}")
| &nbsp;#{translate("stop_on_validation_error")}
li
a(href, ng-click="stop_on_validation_error = false")
i.fa.fa-fw(ng-class="{'fa-check': !stop_on_validation_error}")
| &nbsp;#{translate("ignore_validation_errors")}
li
a(href, ng-click="recompile({check:true})")
i.fa.fa-fw()
| &nbsp;#{translate("run_syntax_check_now")}
a(
href
ng-click="stop()"
ng-show="pdf.compiling",
tooltip=translate('stop_compile')
tooltip-placement="bottom"
)
i.fa.fa-fw.fa-stop()
a.log-btn(
href
ng-click="toggleLogs()"
ng-class="{ 'active': shouldShowLogs == true }"
tooltip=translate('logs_and_output_files')
tooltip-placement="bottom"
)
i.fa.fa-fw.fa-file-text-o
span.label(
ng-show="pdf.logEntries.warnings.length + pdf.logEntries.errors.length > 0"
ng-class="{\
'label-warning': pdf.logEntries.errors.length == 0,\
'label-danger': pdf.logEntries.errors.length > 0\
}"
) {{ pdf.logEntries.errors.length + pdf.logEntries.warnings.length }}
a(
ng-href="{{pdf.downloadUrl || pdf.url}}"
target="_blank"
ng-if="pdf.url"
tooltip=translate('download_pdf')
tooltip-placement="bottom"
)
i.fa.fa-fw.fa-download
.toolbar-right
span.auto-compile-status.small(
ng-show="changesToAutoCompile && !compiling && !autoCompileLintingError"
) #{translate('uncompiled_changes')}
span.auto-compile-status.auto-compile-error.small(
ng-show="autoCompileLintingError"
tooltip-placement="bottom"
tooltip=translate("code_check_failed_explanation")
else
.toolbar.toolbar-pdf(ng-class="{ 'changes-to-autocompile': changesToAutoCompile && !autoCompileLintingError }")
.btn-group.btn-recompile-group#recompile(
dropdown,
tooltip-html="'"+translate('recompile_pdf')+" <span class=\"keyboard-shortcut\">({{modifierKey}} + Enter)</span>'"
tooltip-class="keyboard-tooltip"
tooltip-popup-delay="500"
tooltip-append-to-body="true"
)
i.fa.fa-fw.fa-exclamation-triangle
|
| #{translate("code_check_failed")}
a(
href,
ng-click="switchToFlatLayout('pdf')"
ng-show="ui.pdfLayout == 'sideBySide'"
tooltip=translate('full_screen')
tooltip-placement="bottom"
tooltip-append-to-body="true"
)
i.fa.fa-expand
a(
href,
ng-click="switchToSideBySideLayout('editor')"
ng-show="ui.pdfLayout == 'flat'"
tooltip=translate('split_screen')
tooltip-placement="bottom"
tooltip-append-to-body="true"
)
i.fa.fa-compress
// end of toolbar
// logs view
.pdf-logs(ng-show="shouldShowLogs")
.alert.alert-success(ng-show="pdf.logEntries.all.length == 0 && !pdf.failure")
| #{translate("no_errors_good_job")}
.alert.alert-danger(ng-show="pdf.failure")
strong #{translate("compile_error")}.
span #{translate("generic_failed_compile_message")}.
.alert.alert-danger(ng-show="pdf.failedCheck")
strong #{translate("failed_compile_check")}.
p
p.text-center(ng-show="!check")
a.text-info(
a.btn.btn-recompile(
href,
ng-disabled="pdf.compiling",
ng-click="recompile({try:true})"
) #{translate("failed_compile_check_try")}
| &#32;#{translate("failed_compile_option_or")}&#32;
a.text-info(
href,
ng-disabled="pdf.compiling",
ng-click="recompile({force:true})"
) #{translate("failed_compile_check_ignore")}
| .
div(ng-repeat="entry in pdf.logEntries.all", ng-controller="PdfLogEntryController")
.alert(
ng-class="{\
'alert-danger': entry.level == 'error',\
'alert-warning': entry.level == 'warning',\
'alert-info': entry.level == 'typesetting'\
}"
ng-click="openInEditor(entry)"
)
span.line-no
i.fa.fa-link(aria-hidden="true")
| &nbsp;
span(ng-show="entry.file") {{ entry.file }}
span(ng-show="entry.line") , line {{ entry.line }}
p.entry-message(ng-show="entry.message")
| {{ entry.type }} {{ entry.message }}
.card.card-hint(
ng-if="entry.humanReadableHint"
stop-propagation="click"
ng-click="recompile()"
)
figure.card-hint-icon-container
i.fa.fa-lightbulb-o(aria-hidden="true")
p.card-hint-text(
ng-show="entry.humanReadableHint",
ng-bind-html="wikiEnabled ? entry.humanReadableHint : stripHTMLFromString(entry.humanReadableHint)")
.card-hint-footer.clearfix
.card-hint-ext-link(ng-if="wikiEnabled && entry.extraInfoURL")
a(
ng-href="{{ entry.extraInfoURL }}",
ng-click="trackLogHintsLearnMore()"
target="_blank"
)
i.fa.fa-external-link
|&nbsp;#{translate("log_hint_extra_info")}
p.entry-content(ng-show="entry.content") {{ entry.content.trim() }}
div
.files-dropdown-container
a.btn.btn-default.btn-sm(
href,
tooltip=translate('clear_cached_files'),
tooltip-placement="top",
tooltip-append-to-body="true",
ng-click="openClearCacheModal()"
)
i.fa.fa-trash-o
| &nbsp;
div.files-dropdown(
ng-class="shouldDropUp ? 'dropup' : 'dropdown'"
dropdown
)
a.btn.btn-default.btn-sm(
href
dropdown-toggle
i.fa.fa-refresh(
ng-class="{'fa-spin': pdf.compiling }"
)
| !{translate("other_logs_and_files")}
span.caret
ul.dropdown-menu.dropdown-menu-right
li(ng-repeat="file in pdf.outputFiles")
a(
href="{{file.url}}"
target="_blank"
) {{ file.name }}
a.btn.btn-info.btn-sm(href, ng-click="toggleRawLog()")
span(ng-show="!pdf.showRawLog") #{translate("view_raw_logs")}
span(ng-show="pdf.showRawLog") #{translate("hide_raw_logs")}
span.btn-recompile-label(ng-show="!pdf.compiling") #{translate("recompile")}
span.btn-recompile-label(ng-show="pdf.compiling") #{translate("compiling")}…
a.btn.btn-recompile.dropdown-toggle(
href,
ng-disabled="pdf.compiling",
dropdown-toggle
)
span.caret
ul.dropdown-menu.dropdown-menu-left
li.dropdown-header #{translate("auto_compile")}
li
a(href, ng-click="autocompile_enabled = true")
i.fa.fa-fw(ng-class="{'fa-check': autocompile_enabled}")
| &nbsp;#{translate('on')}
li
a(href, ng-click="autocompile_enabled = false")
i.fa.fa-fw(ng-class="{'fa-check': !autocompile_enabled}")
| &nbsp;#{translate('off')}
li.dropdown-header #{translate("compile_mode")}
li
a(href, ng-click="draft = false")
i.fa.fa-fw(ng-class="{'fa-check': !draft}")
| &nbsp;#{translate("normal")}
li
a(href, ng-click="draft = true")
i.fa.fa-fw(ng-class="{'fa-check': draft}")
| &nbsp;#{translate("fast")}&nbsp;
span.subdued [draft]
li.dropdown-header #{translate("compile_time_checks")}
li
a(href, ng-click="stop_on_validation_error = true")
i.fa.fa-fw(ng-class="{'fa-check': stop_on_validation_error}")
| &nbsp;#{translate("stop_on_validation_error")}
li
a(href, ng-click="stop_on_validation_error = false")
i.fa.fa-fw(ng-class="{'fa-check': !stop_on_validation_error}")
| &nbsp;#{translate("ignore_validation_errors")}
li
a(href, ng-click="recompile({check:true})")
i.fa.fa-fw()
| &nbsp;#{translate("run_syntax_check_now")}
a(
href
ng-click="stop()"
ng-show="pdf.compiling",
tooltip=translate('stop_compile')
tooltip-placement="bottom"
)
i.fa.fa-fw.fa-stop()
a.log-btn(
href
ng-click="toggleLogs()"
ng-class="{ 'active': shouldShowLogs == true }"
tooltip=translate('logs_and_output_files')
tooltip-placement="bottom"
)
i.fa.fa-fw.fa-file-text-o
span.label(
ng-show="pdf.logEntries.warnings.length + pdf.logEntries.errors.length > 0"
ng-class="{\
'label-warning': pdf.logEntries.errors.length == 0,\
'label-danger': pdf.logEntries.errors.length > 0\
}"
) {{ pdf.logEntries.errors.length + pdf.logEntries.warnings.length }}
a(
ng-href="{{pdf.downloadUrl || pdf.url}}"
target="_blank"
ng-if="pdf.url"
tooltip=translate('download_pdf')
tooltip-placement="bottom"
)
i.fa.fa-fw.fa-download
.toolbar-right
span.auto-compile-status.small(
ng-show="changesToAutoCompile && !compiling && !autoCompileLintingError"
) #{translate('uncompiled_changes')}
span.auto-compile-status.auto-compile-error.small(
ng-show="autoCompileLintingError"
tooltip-placement="bottom"
tooltip=translate("code_check_failed_explanation")
tooltip-append-to-body="true"
)
i.fa.fa-fw.fa-exclamation-triangle
|
| #{translate("code_check_failed")}
a(
href,
ng-click="switchToFlatLayout('pdf')"
ng-show="ui.pdfLayout == 'sideBySide'"
tooltip=translate('full_screen')
tooltip-placement="bottom"
tooltip-append-to-body="true"
)
i.fa.fa-expand
a(
href,
ng-click="switchToSideBySideLayout('editor')"
ng-show="ui.pdfLayout == 'flat'"
tooltip=translate('split_screen')
tooltip-placement="bottom"
tooltip-append-to-body="true"
)
i.fa.fa-compress
// end of toolbar
pre(ng-bind="pdf.rawLog", ng-show="pdf.showRawLog")
// logs view
.pdf-logs(ng-show="shouldShowLogs")
.alert.alert-success(ng-show="pdf.logEntries.all.length == 0 && !pdf.failure")
| #{translate("no_errors_good_job")}
.alert.alert-danger(ng-show="pdf.failure")
strong #{translate("compile_error")}.
span #{translate("generic_failed_compile_message")}.
.alert.alert-danger(ng-show="pdf.failedCheck")
strong #{translate("failed_compile_check")}.
p
p.text-center(ng-show="!check")
a.text-info(
href,
ng-disabled="pdf.compiling",
ng-click="recompile({try:true})"
) #{translate("failed_compile_check_try")}
| &#32;#{translate("failed_compile_option_or")}&#32;
a.text-info(
href,
ng-disabled="pdf.compiling",
ng-click="recompile({force:true})"
) #{translate("failed_compile_check_ignore")}
| .
div(ng-repeat="entry in pdf.logEntries.all", ng-controller="PdfLogEntryController")
.alert(
ng-class="{\
'alert-danger': entry.level == 'error',\
'alert-warning': entry.level == 'warning',\
'alert-info': entry.level == 'typesetting'\
}"
ng-click="openInEditor(entry)"
)
span.line-no
i.fa.fa-link(aria-hidden="true")
| &nbsp;
span(ng-show="entry.file") {{ entry.file }}
span(ng-show="entry.line") , line {{ entry.line }}
p.entry-message(ng-show="entry.message")
| {{ entry.type }} {{ entry.message }}
.card.card-hint(
ng-if="entry.humanReadableHint"
stop-propagation="click"
)
figure.card-hint-icon-container
i.fa.fa-lightbulb-o(aria-hidden="true")
p.card-hint-text(
ng-show="entry.humanReadableHint",
ng-bind-html="wikiEnabled ? entry.humanReadableHint : stripHTMLFromString(entry.humanReadableHint)")
.card-hint-footer.clearfix
.card-hint-ext-link(ng-if="wikiEnabled && entry.extraInfoURL")
a(
ng-href="{{ entry.extraInfoURL }}",
ng-click="trackLogHintsLearnMore()"
target="_blank"
)
i.fa.fa-external-link
|&nbsp;#{translate("log_hint_extra_info")}
p.entry-content(ng-show="entry.content") {{ entry.content.trim() }}
div
.files-dropdown-container
a.btn.btn-default.btn-sm(
href,
tooltip=translate('clear_cached_files'),
tooltip-placement="top",
tooltip-append-to-body="true",
ng-click="openClearCacheModal()"
)
i.fa.fa-trash-o
| &nbsp;
div.files-dropdown(
ng-class="shouldDropUp ? 'dropup' : 'dropdown'"
dropdown
)
a.btn.btn-default.btn-sm(
href
dropdown-toggle
)
| !{translate("other_logs_and_files")}
span.caret
ul.dropdown-menu.dropdown-menu-right
li(ng-repeat="file in pdf.outputFiles")
a(
href="{{file.url}}"
target="_blank"
) {{ file.name }}
a.btn.btn-info.btn-sm(href, ng-click="toggleRawLog()")
span(ng-show="!pdf.showRawLog") #{translate("view_raw_logs")}
span(ng-show="pdf.showRawLog") #{translate("hide_raw_logs")}
pre(ng-bind="pdf.rawLog", ng-show="pdf.showRawLog")
// non-log views (pdf and errors)
@@ -6,5 +6,16 @@
"expand",
"collapse",
"show_outline",
"hide_outline"
"hide_outline",
"compiling",
"recompile",
"auto_compile",
"on",
"off",
"compile_mode",
"normal",
"fast",
"stop_on_validation_error",
"ignore_validation_errors",
"run_syntax_check_now"
]
@@ -0,0 +1,40 @@
import React from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'
function PreviewLogEntry({ file, line, message, content, raw, level }) {
const logEntryClasses = classNames('alert', {
'alert-danger': level === 'error',
'alert-warning': level === 'warning',
'alert-info': level === 'typesetting'
})
return (
<div className={logEntryClasses}>
<span className="line-no">
<i className="fa fa-link" aria-hidden="true" />
{file ? <span>{file}</span> : null}
{line ? <span>, {line}</span> : null}
</span>
{message ? (
<p className="entry-message">
{level} {message}
</p>
) : null}
{content ? <p className="entry-content">{content.trim()}</p> : null}
</div>
)
}
PreviewLogEntry.propTypes = {
file: PropTypes.string,
// `line should be either a number or null (i.e. not required), but currently sometimes we get
// an empty string (from BibTeX errors), which is why we're using `any` here. We should revert
// to PropTypes.number (not required) once we fix that.
line: PropTypes.any,
message: PropTypes.string,
content: PropTypes.string,
raw: PropTypes.string,
level: PropTypes.string.isRequired
}
export default PreviewLogEntry
@@ -0,0 +1,23 @@
import React from 'react'
import PropTypes from 'prop-types'
import PreviewLogEntry from './preview-log-entry'
function PreviewLogsPane({ logEntries }) {
return (
<div className="pdf-logs">
{logEntries && logEntries.length > 0 ? (
logEntries.map((logEntry, idx) => (
<PreviewLogEntry key={idx} {...logEntry} />
))
) : (
<div>No logs</div>
)}
</div>
)
}
PreviewLogsPane.propTypes = {
logEntries: PropTypes.array
}
export default PreviewLogsPane
@@ -0,0 +1,50 @@
import React from 'react'
import PropTypes from 'prop-types'
import PreviewToolbar from './preview-toolbar'
import PreviewLogsPane from './preview-logs-pane'
function PreviewPane({
compilerState,
logEntries,
onRecompile,
onRunSyntaxCheckNow,
onSetAutoCompile,
onSetDraftMode,
onSetSyntaxCheck,
onToggleLogs,
shouldShowLogs
}) {
return (
<>
<PreviewToolbar
compilerState={compilerState}
onRecompile={onRecompile}
onRunSyntaxCheckNow={onRunSyntaxCheckNow}
onSetAutoCompile={onSetAutoCompile}
onSetDraftMode={onSetDraftMode}
onSetSyntaxCheck={onSetSyntaxCheck}
onToggleLogs={onToggleLogs}
/>
{shouldShowLogs ? <PreviewLogsPane logEntries={logEntries} /> : null}
</>
)
}
PreviewPane.propTypes = {
compilerState: PropTypes.shape({
isAutoCompileOn: PropTypes.bool.isRequired,
isCompiling: PropTypes.bool.isRequired,
isDraftModeOn: PropTypes.bool.isRequired,
isSyntaxCheckOn: PropTypes.bool.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
}
export default PreviewPane
@@ -0,0 +1,125 @@
import React from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'
import { Dropdown, MenuItem } from 'react-bootstrap'
import { useTranslation } from 'react-i18next'
function PreviewRecompileButton({
compilerState: {
isAutoCompileOn,
isCompiling,
isDraftModeOn,
isSyntaxCheckOn
},
onRecompile,
onRunSyntaxCheckNow,
onSetAutoCompile,
onSetDraftMode,
onSetSyntaxCheck
}) {
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)
}
function handleSelectAutoCompileOff() {
onSetAutoCompile(false)
}
function handleSelectDraftModeOn() {
onSetDraftMode(true)
}
function handleSelectDraftModeOff() {
onSetDraftMode(false)
}
function handleSelectSyntaxCheckOn() {
onSetSyntaxCheck(true)
}
function handleSelectSyntaxCheckOff() {
onSetSyntaxCheck(false)
}
return (
<Dropdown id="pdf-recompile-dropdown" className="btn-recompile-group">
<button className="btn btn-recompile" onClick={onRecompile}>
<i className={iconClasses.recompile} aria-hidden="true" />
{isCompiling ? (
<span className="btn-recompile-label">
{t('compiling')}
&hellip;
</span>
) : (
<span className="btn-recompile-label">{t('recompile')}</span>
)}
</button>
<Dropdown.Toggle className="btn btn-recompile" />
<Dropdown.Menu>
<MenuItem header>{t('auto_compile')}</MenuItem>
<MenuItem onSelect={handleSelectAutoCompileOn}>
<i className={iconClasses.autoCompileOn} aria-hidden="true" />
{t('on')}
</MenuItem>
<MenuItem onSelect={handleSelectAutoCompileOff}>
<i className={iconClasses.autoCompileOff} aria-hidden="true" />
{t('off')}
</MenuItem>
<MenuItem header>{t('compile_mode')}</MenuItem>
<MenuItem onSelect={handleSelectDraftModeOff}>
<i className={iconClasses.compileModeNormal} aria-hidden="true" />
{t('normal')}
</MenuItem>
<MenuItem onSelect={handleSelectDraftModeOn}>
<i className={iconClasses.compileModeDraft} aria-hidden="true" />
{t('fast')} <span className="subdued">[draft]</span>
</MenuItem>
<MenuItem header>Syntax Checks</MenuItem>
<MenuItem onSelect={handleSelectSyntaxCheckOn}>
<i className={iconClasses.syntaxCheckOn} aria-hidden="true" />
{t('stop_on_validation_error')}
</MenuItem>
<MenuItem onSelect={handleSelectSyntaxCheckOff}>
<i className={iconClasses.syntaxCheckOff} aria-hidden="true" />
{t('ignore_validation_errors')}
</MenuItem>
<MenuItem onSelect={onRunSyntaxCheckNow}>
<i className="fa fa-fw" aria-hidden="true" />
{t('run_syntax_check_now')}
</MenuItem>
</Dropdown.Menu>
</Dropdown>
)
}
PreviewRecompileButton.propTypes = {
compilerState: PropTypes.shape({
isAutoCompileOn: PropTypes.bool.isRequired,
isCompiling: PropTypes.bool.isRequired,
isDraftModeOn: PropTypes.bool.isRequired,
isSyntaxCheckOn: PropTypes.bool.isRequired
}),
onRecompile: PropTypes.func.isRequired,
onRunSyntaxCheckNow: PropTypes.func.isRequired,
onSetAutoCompile: PropTypes.func.isRequired,
onSetDraftMode: PropTypes.func.isRequired,
onSetSyntaxCheck: PropTypes.func.isRequired
}
export default PreviewRecompileButton
@@ -0,0 +1,46 @@
import React from 'react'
import PropTypes from 'prop-types'
import PreviewRecompileButton from './preview-recompile-button'
function PreviewToolbar({
compilerState,
onRecompile,
onRunSyntaxCheckNow,
onSetAutoCompile,
onSetDraftMode,
onSetSyntaxCheck,
onToggleLogs
}) {
return (
<div className="toolbar toolbar-pdf">
<PreviewRecompileButton
compilerState={compilerState}
onRecompile={onRecompile}
onRunSyntaxCheckNow={onRunSyntaxCheckNow}
onSetAutoCompile={onSetAutoCompile}
onSetDraftMode={onSetDraftMode}
onSetSyntaxCheck={onSetSyntaxCheck}
/>
<button className="btn btn-sm btn-secondary" onClick={onToggleLogs}>
Toggle logs
</button>
</div>
)
}
PreviewToolbar.propTypes = {
compilerState: PropTypes.shape({
isAutoCompileOn: PropTypes.bool.isRequired,
isCompiling: PropTypes.bool.isRequired,
isDraftModeOn: PropTypes.bool.isRequired,
isSyntaxCheckOn: PropTypes.bool.isRequired
}),
onRecompile: PropTypes.func.isRequired,
onRunSyntaxCheckNow: PropTypes.func.isRequired,
onSetAutoCompile: PropTypes.func.isRequired,
onSetDraftMode: PropTypes.func.isRequired,
onSetSyntaxCheck: PropTypes.func.isRequired,
onToggleLogs: PropTypes.func.isRequired
}
export default PreviewToolbar
@@ -11,6 +11,7 @@
import './controllers/PdfController'
import './controllers/PdfViewToggleController'
import '../pdfng/directives/pdfJs'
let PdfManager
export default (PdfManager = class PdfManager {
@@ -1,6 +1,8 @@
import App from '../../../base'
import HumanReadableLogs from '../../human-readable-logs/HumanReadableLogs'
import BibLogParser from 'libs/bib-log-parser'
import PreviewPane from '../../../features/preview/components/preview-pane'
import { react2angular } from 'react2angular'
import 'ace/ace'
const AUTO_COMPILE_MAX_WAIT = 5000
// We add a 1 second debounce to sending user changes to server if they aren't
@@ -807,10 +809,12 @@ App.controller('PdfController', function(
}
$scope.toggleLogs = function() {
$scope.shouldShowLogs = !$scope.shouldShowLogs
if ($scope.shouldShowLogs) {
eventTracking.sendMBOnce('ide-open-logs-once')
}
$scope.$applyAsync(() => {
$scope.shouldShowLogs = !$scope.shouldShowLogs
if ($scope.shouldShowLogs) {
eventTracking.sendMBOnce('ide-open-logs-once')
}
})
}
$scope.showPdf = function() {
@@ -839,6 +843,27 @@ App.controller('PdfController', function(
ide.editorManager.openDoc(doc, { gotoLine: line })
})
}
$scope.setAutoCompile = function(isOn) {
$scope.$applyAsync(function() {
$scope.autocompile_enabled = isOn
})
}
$scope.setDraftMode = function(isOn) {
$scope.$applyAsync(function() {
$scope.draft = isOn
})
}
$scope.setSyntaxCheck = function(isOn) {
$scope.$applyAsync(function() {
$scope.stop_on_validation_error = isOn
})
}
$scope.runSyntaxCheckNow = function() {
$scope.$applyAsync(function() {
$scope.recompile({ check: true })
})
}
})
App.factory('synctex', function(ide, $http, $q) {
@@ -1043,3 +1068,6 @@ App.controller('ClearCacheModalController', function($scope, $modalInstance) {
$scope.cancel = () => $modalInstance.dismiss('cancel')
})
// Wrap React component as Angular component. Only needed for "top-level" component
App.component('previewPane', react2angular(PreviewPane))
@@ -77,6 +77,10 @@
}
}
.btn-recompile-label {
margin-left: @line-height-computed / 4;
}
.pdf-viewer {
iframe {
width: 100%;