mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #3242 from overleaf/jel-add-recompile-from-scratch
Add recompile from scratch option GitOrigin-RevId: 59836df9049e307acb11824058024919409ea4a4
This commit is contained in:
parent
4690b2ec86
commit
f8a8c9bbd6
8 changed files with 191 additions and 10 deletions
|
@ -3,11 +3,13 @@ div.full-size.pdf(ng-controller="PdfController")
|
|||
preview-pane(
|
||||
compiler-state=`{
|
||||
isAutoCompileOn: autocompile_enabled,
|
||||
isClearingCache: pdf.clearingCache,
|
||||
isCompiling: pdf.compiling,
|
||||
isDraftModeOn: draft,
|
||||
isSyntaxCheckOn: stop_on_validation_error,
|
||||
logEntries: pdf.logEntries ? pdf.logEntries : {}
|
||||
}`
|
||||
on-clear-cache="clearCache"
|
||||
on-recompile="recompile"
|
||||
on-run-syntax-check-now="runSyntaxCheckNow"
|
||||
on-set-auto-compile="setAutoCompile"
|
||||
|
@ -379,6 +381,7 @@ script(type='text/ng-template', id='clearCacheModalTemplate')
|
|||
.modal-body
|
||||
p #{translate("clear_cache_explanation")}
|
||||
p #{translate("clear_cache_is_safe")}
|
||||
.alert.alert-danger(ng-if="state.error") #{translate("generic_something_went_wrong")}.
|
||||
.modal-footer
|
||||
button.btn.btn-default(
|
||||
ng-click="cancel()"
|
||||
|
|
|
@ -29,5 +29,8 @@
|
|||
"your_project_has_errors",
|
||||
"view_warnings",
|
||||
"view_logs",
|
||||
"view_pdf"
|
||||
"view_pdf",
|
||||
"recompile_from_scratch",
|
||||
"run_syntax_check_now",
|
||||
"toggle_compile_options_menu"
|
||||
]
|
||||
|
|
|
@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next'
|
|||
|
||||
function PreviewPane({
|
||||
compilerState,
|
||||
onClearCache,
|
||||
onRecompile,
|
||||
onRunSyntaxCheckNow,
|
||||
onSetAutoCompile,
|
||||
|
@ -35,6 +36,7 @@ function PreviewPane({
|
|||
compilerState={compilerState}
|
||||
logsState={{ nErrors, nWarnings, nLogEntries }}
|
||||
showLogs={showLogs}
|
||||
onClearCache={onClearCache}
|
||||
onRecompile={onRecompile}
|
||||
onRunSyntaxCheckNow={onRunSyntaxCheckNow}
|
||||
onSetAutoCompile={onSetAutoCompile}
|
||||
|
@ -67,6 +69,7 @@ PreviewPane.propTypes = {
|
|||
isSyntaxCheckOn: PropTypes.bool.isRequired,
|
||||
logEntries: PropTypes.object.isRequired
|
||||
}),
|
||||
onClearCache: PropTypes.func.isRequired,
|
||||
onRecompile: PropTypes.func.isRequired,
|
||||
onRunSyntaxCheckNow: PropTypes.func.isRequired,
|
||||
onSetAutoCompile: PropTypes.func.isRequired,
|
||||
|
|
|
@ -7,10 +7,12 @@ import Icon from '../../../shared/components/icon'
|
|||
function PreviewRecompileButton({
|
||||
compilerState: {
|
||||
isAutoCompileOn,
|
||||
isClearingCache,
|
||||
isCompiling,
|
||||
isDraftModeOn,
|
||||
isSyntaxCheckOn
|
||||
},
|
||||
onClearCache,
|
||||
onRecompile,
|
||||
onRunSyntaxCheckNow,
|
||||
onSetAutoCompile,
|
||||
|
@ -19,6 +21,16 @@ function PreviewRecompileButton({
|
|||
}) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
function handleRecompileFromScratch() {
|
||||
onClearCache()
|
||||
.then(() => {
|
||||
onRecompile()
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error)
|
||||
})
|
||||
}
|
||||
|
||||
function handleSelectAutoCompileOn() {
|
||||
onSetAutoCompile(true)
|
||||
}
|
||||
|
@ -47,7 +59,7 @@ function PreviewRecompileButton({
|
|||
<Dropdown id="pdf-recompile-dropdown" className="btn-recompile-group">
|
||||
<button className="btn btn-recompile" onClick={onRecompile}>
|
||||
<Icon type="refresh" spin={isCompiling} />
|
||||
{isCompiling ? (
|
||||
{isCompiling || isClearingCache ? (
|
||||
<span className="btn-recompile-label">
|
||||
{t('compiling')}
|
||||
…
|
||||
|
@ -56,7 +68,10 @@ function PreviewRecompileButton({
|
|||
<span className="btn-recompile-label">{t('recompile')}</span>
|
||||
)}
|
||||
</button>
|
||||
<Dropdown.Toggle className="btn btn-recompile" />
|
||||
<Dropdown.Toggle
|
||||
aria-label={t('toggle_compile_options_menu')}
|
||||
className="btn btn-recompile"
|
||||
/>
|
||||
<Dropdown.Menu>
|
||||
<MenuItem header>{t('auto_compile')}</MenuItem>
|
||||
<MenuItem onSelect={handleSelectAutoCompileOn}>
|
||||
|
@ -89,6 +104,14 @@ function PreviewRecompileButton({
|
|||
<Icon type="" modifier="fw" />
|
||||
{t('run_syntax_check_now')}
|
||||
</MenuItem>
|
||||
<MenuItem divider />
|
||||
<MenuItem
|
||||
onSelect={handleRecompileFromScratch}
|
||||
disabled={isCompiling || isClearingCache}
|
||||
aria-disabled={!!(isCompiling || isClearingCache)}
|
||||
>
|
||||
{t('recompile_from_scratch')}
|
||||
</MenuItem>
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
)
|
||||
|
@ -97,11 +120,13 @@ function PreviewRecompileButton({
|
|||
PreviewRecompileButton.propTypes = {
|
||||
compilerState: PropTypes.shape({
|
||||
isAutoCompileOn: PropTypes.bool.isRequired,
|
||||
isClearingCache: PropTypes.bool.isRequired,
|
||||
isCompiling: PropTypes.bool.isRequired,
|
||||
isDraftModeOn: PropTypes.bool.isRequired,
|
||||
isSyntaxCheckOn: PropTypes.bool.isRequired,
|
||||
logEntries: PropTypes.object.isRequired
|
||||
}),
|
||||
onClearCache: PropTypes.func.isRequired,
|
||||
onRecompile: PropTypes.func.isRequired,
|
||||
onRunSyntaxCheckNow: PropTypes.func.isRequired,
|
||||
onSetAutoCompile: PropTypes.func.isRequired,
|
||||
|
|
|
@ -6,6 +6,7 @@ import PreviewLogsToggleButton from './preview-logs-toggle-button'
|
|||
function PreviewToolbar({
|
||||
compilerState,
|
||||
logsState,
|
||||
onClearCache,
|
||||
onRecompile,
|
||||
onRunSyntaxCheckNow,
|
||||
onSetAutoCompile,
|
||||
|
@ -24,6 +25,7 @@ function PreviewToolbar({
|
|||
onSetAutoCompile={onSetAutoCompile}
|
||||
onSetDraftMode={onSetDraftMode}
|
||||
onSetSyntaxCheck={onSetSyntaxCheck}
|
||||
onClearCache={onClearCache}
|
||||
/>
|
||||
</div>
|
||||
<div className="toolbar-pdf-right">
|
||||
|
@ -51,6 +53,7 @@ PreviewToolbar.propTypes = {
|
|||
nLogEntries: PropTypes.number.isRequired
|
||||
}),
|
||||
showLogs: PropTypes.bool.isRequired,
|
||||
onClearCache: PropTypes.func.isRequired,
|
||||
onRecompile: PropTypes.func.isRequired,
|
||||
onRunSyntaxCheckNow: PropTypes.func.isRequired,
|
||||
onSetAutoCompile: PropTypes.func.isRequired,
|
||||
|
|
|
@ -20,12 +20,14 @@ App.controller('PdfController', function(
|
|||
$modal,
|
||||
synctex,
|
||||
eventTracking,
|
||||
localStorage
|
||||
localStorage,
|
||||
$q
|
||||
) {
|
||||
let autoCompile = true
|
||||
|
||||
// pdf.view = uncompiled | pdf | errors
|
||||
$scope.pdf.view = $scope.pdf.url ? 'pdf' : 'uncompiled'
|
||||
$scope.pdf.clearingCache = false
|
||||
$scope.shouldShowLogs = false
|
||||
$scope.wikiEnabled = window.wikiEnabled
|
||||
|
||||
|
@ -796,7 +798,10 @@ App.controller('PdfController', function(
|
|||
}
|
||||
|
||||
$scope.clearCache = function() {
|
||||
return $http({
|
||||
$scope.pdf.clearingCache = true
|
||||
const deferred = $q.defer()
|
||||
|
||||
$http({
|
||||
url: `/project/${$scope.project_id}/output`,
|
||||
method: 'DELETE',
|
||||
params: {
|
||||
|
@ -806,6 +811,20 @@ App.controller('PdfController', function(
|
|||
'X-Csrf-Token': window.csrfToken
|
||||
}
|
||||
})
|
||||
.then(function(response) {
|
||||
$scope.pdf.clearingCache = false
|
||||
return deferred.resolve()
|
||||
})
|
||||
.catch(function(response) {
|
||||
console.error(response)
|
||||
const error = response.data
|
||||
$scope.pdf.clearingCache = false
|
||||
$scope.pdf.renderingError = false
|
||||
$scope.pdf.error = true
|
||||
$scope.pdf.view = 'errors'
|
||||
return deferred.reject(error)
|
||||
})
|
||||
return deferred.promise
|
||||
}
|
||||
|
||||
$scope.toggleLogs = function() {
|
||||
|
@ -1056,14 +1075,20 @@ App.controller('PdfLogEntryController', function($scope, ide, eventTracking) {
|
|||
})
|
||||
|
||||
App.controller('ClearCacheModalController', function($scope, $modalInstance) {
|
||||
$scope.state = { inflight: false }
|
||||
$scope.state = { error: false, inflight: false }
|
||||
|
||||
$scope.clear = function() {
|
||||
$scope.state.inflight = true
|
||||
$scope.clearCache().then(function() {
|
||||
$scope.state.inflight = false
|
||||
$modalInstance.close()
|
||||
})
|
||||
$scope
|
||||
.clearCache()
|
||||
.then(function() {
|
||||
$scope.state.inflight = false
|
||||
$modalInstance.close()
|
||||
})
|
||||
.catch(function() {
|
||||
$scope.state.error = true
|
||||
$scope.state.inflight = false
|
||||
})
|
||||
}
|
||||
|
||||
$scope.cancel = () => $modalInstance.dismiss('cancel')
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"n_warnings_plural": "__count__ warnings",
|
||||
"n_errors": "__count__ error",
|
||||
"n_errors_plural": "__count__ errors",
|
||||
"toggle_compile_options_menu": "Toggle compile options menu",
|
||||
"view_pdf": "View PDF",
|
||||
"your_project_has_errors": "Your project has errors",
|
||||
"view_warnings": "View warnings",
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
import React from 'react'
|
||||
import sinon from 'sinon'
|
||||
import { screen, render, fireEvent } from '@testing-library/react'
|
||||
import PreviewRecompileButton from '../../../../../frontend/js/features/preview/components/preview-recompile-button'
|
||||
const { expect } = require('chai')
|
||||
|
||||
describe('<PreviewRecompileButton />', function() {
|
||||
let onRecompile, onClearCache
|
||||
|
||||
beforeEach(function() {
|
||||
onRecompile = sinon.stub().resolves()
|
||||
onClearCache = sinon.stub().resolves()
|
||||
})
|
||||
|
||||
it('renders all items', function() {
|
||||
renderPreviewRecompileButton()
|
||||
|
||||
const menuItems = screen.getAllByRole('menuitem')
|
||||
expect(menuItems.length).to.equal(8)
|
||||
expect(menuItems.map(item => item.textContent)).to.deep.equal([
|
||||
'On',
|
||||
'Off',
|
||||
'Normal',
|
||||
'Fast [draft]',
|
||||
'Check syntax before compile',
|
||||
"Don't check syntax",
|
||||
'Run syntax check now',
|
||||
'Recompile from scratch'
|
||||
])
|
||||
|
||||
const menuHeadingItems = screen.getAllByRole('heading')
|
||||
expect(menuHeadingItems.length).to.equal(3)
|
||||
expect(menuHeadingItems.map(item => item.textContent)).to.deep.equal([
|
||||
'Auto Compile',
|
||||
'Compile Mode',
|
||||
'Syntax Checks'
|
||||
])
|
||||
})
|
||||
|
||||
describe('Recompile from scratch', function() {
|
||||
describe('click', function() {
|
||||
it('should call onClearCache and onRecompile', async function() {
|
||||
renderPreviewRecompileButton()
|
||||
|
||||
const button = screen.getByRole('menuitem', {
|
||||
name: 'Recompile from scratch'
|
||||
})
|
||||
await fireEvent.click(button)
|
||||
expect(onClearCache).to.have.been.calledOnce
|
||||
expect(onRecompile).to.have.been.calledOnce
|
||||
})
|
||||
})
|
||||
describe('processing', function() {
|
||||
it('shows processing view and disable menuItem when clearing cache', function() {
|
||||
renderPreviewRecompileButton({ isClearingCache: true })
|
||||
|
||||
screen.getByRole('button', { name: 'Compiling …' })
|
||||
expect(
|
||||
screen
|
||||
.getByRole('menuitem', {
|
||||
name: 'Recompile from scratch'
|
||||
})
|
||||
.getAttribute('aria-disabled')
|
||||
).to.equal('true')
|
||||
expect(
|
||||
screen
|
||||
.getByRole('menuitem', {
|
||||
name: 'Recompile from scratch'
|
||||
})
|
||||
.closest('li')
|
||||
.getAttribute('class')
|
||||
).to.equal('disabled')
|
||||
})
|
||||
|
||||
it('shows processing view and disable menuItem when recompiling', function() {
|
||||
renderPreviewRecompileButton({ isCompiling: true })
|
||||
|
||||
screen.getByRole('button', { name: 'Compiling …' })
|
||||
expect(
|
||||
screen
|
||||
.getByRole('menuitem', {
|
||||
name: 'Recompile from scratch'
|
||||
})
|
||||
.getAttribute('aria-disabled')
|
||||
).to.equal('true')
|
||||
expect(
|
||||
screen
|
||||
.getByRole('menuitem', {
|
||||
name: 'Recompile from scratch'
|
||||
})
|
||||
.closest('li')
|
||||
.getAttribute('class')
|
||||
).to.equal('disabled')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function renderPreviewRecompileButton(compilerState = {}) {
|
||||
render(
|
||||
<PreviewRecompileButton
|
||||
compilerState={{
|
||||
isAutoCompileOn: true,
|
||||
isClearingCache: false,
|
||||
isCompiling: false,
|
||||
isDraftModeOn: false,
|
||||
isSyntaxCheckOn: false,
|
||||
...compilerState
|
||||
}}
|
||||
onRecompile={onRecompile}
|
||||
onRunSyntaxCheckNow={() => {}}
|
||||
onSetAutoCompile={() => {}}
|
||||
onSetDraftMode={() => {}}
|
||||
onSetSyntaxCheck={() => {}}
|
||||
onClearCache={onClearCache}
|
||||
/>
|
||||
)
|
||||
}
|
||||
})
|
Loading…
Reference in a new issue