mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #8483 from overleaf/jpa-faster-compiles-feedback-ui
[web] faster compiles feedback UI GitOrigin-RevId: 9feea47503aa6bddf51adb73b8c9fbef394fda14
This commit is contained in:
parent
9d913a0cea
commit
bfad0841a4
13 changed files with 266 additions and 17 deletions
|
@ -88,7 +88,9 @@ module.exports = CompileController = {
|
||||||
if (pdfDownloadDomain && outputUrlPrefix) {
|
if (pdfDownloadDomain && outputUrlPrefix) {
|
||||||
pdfDownloadDomain += outputUrlPrefix
|
pdfDownloadDomain += outputUrlPrefix
|
||||||
}
|
}
|
||||||
|
let showFasterCompilesFeedbackUI = false
|
||||||
if (limits?.emitCompileResultEvent) {
|
if (limits?.emitCompileResultEvent) {
|
||||||
|
showFasterCompilesFeedbackUI = true
|
||||||
AnalyticsManager.recordEventForSession(
|
AnalyticsManager.recordEventForSession(
|
||||||
req.session,
|
req.session,
|
||||||
'compile-result-backend',
|
'compile-result-backend',
|
||||||
|
@ -111,6 +113,7 @@ module.exports = CompileController = {
|
||||||
stats,
|
stats,
|
||||||
timings,
|
timings,
|
||||||
pdfDownloadDomain,
|
pdfDownloadDomain,
|
||||||
|
showFasterCompilesFeedbackUI,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -125,6 +125,11 @@
|
||||||
"expand": "",
|
"expand": "",
|
||||||
"export_project_to_github": "",
|
"export_project_to_github": "",
|
||||||
"fast": "",
|
"fast": "",
|
||||||
|
"faster_compiles_feedback_question": "",
|
||||||
|
"faster_compiles_feedback_seems_faster": "",
|
||||||
|
"faster_compiles_feedback_seems_same": "",
|
||||||
|
"faster_compiles_feedback_seems_slower": "",
|
||||||
|
"faster_compiles_feedback_thanks": "",
|
||||||
"file_already_exists": "",
|
"file_already_exists": "",
|
||||||
"file_already_exists_in_this_location": "",
|
"file_already_exists_in_this_location": "",
|
||||||
"file_name": "",
|
"file_name": "",
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
import { memo, useEffect, useRef, useState } from 'react'
|
||||||
|
import { Button, Alert } from 'react-bootstrap'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import Icon from '../../../shared/components/icon'
|
||||||
|
import { sendMB } from '../../../infrastructure/event-tracking'
|
||||||
|
import usePersistedState from '../../../shared/hooks/use-persisted-state'
|
||||||
|
import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
|
||||||
|
import { useProjectContext } from '../../../shared/context/project-context'
|
||||||
|
|
||||||
|
const SAY_THANKS_TIMEOUT = 10 * 1000
|
||||||
|
|
||||||
|
function FasterCompilesFeedbackContent() {
|
||||||
|
const { clsiServerId, deliveryLatencies, pdfSize, pdfUrl } =
|
||||||
|
useCompileContext()
|
||||||
|
const { _id: projectId } = useProjectContext()
|
||||||
|
|
||||||
|
const [incrementalCompiles, setIncrementalCompiles] = useState(0)
|
||||||
|
const [hasRatedProject, setHasRatedProject] = usePersistedState(
|
||||||
|
`faster-compiles-feedback:${projectId}`,
|
||||||
|
false,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
const [dismiss, setDismiss] = usePersistedState(
|
||||||
|
'faster-compiles-feedback:dismiss',
|
||||||
|
false,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
const [sayThanks, setSayThanks] = useState(false)
|
||||||
|
const lastClsiServerId = useRef('')
|
||||||
|
const lastPdfUrl = useRef('')
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
!pdfUrl ||
|
||||||
|
!lastPdfUrl.current ||
|
||||||
|
clsiServerId !== lastClsiServerId.current
|
||||||
|
) {
|
||||||
|
// Reset history after
|
||||||
|
// - clearing cache / server error (both reset pdfUrl)
|
||||||
|
// - initial compile after reset of pdfUrl
|
||||||
|
// - switching the clsi server, aka we get a _slow_ full compile.
|
||||||
|
setIncrementalCompiles(0)
|
||||||
|
lastClsiServerId.current = clsiServerId
|
||||||
|
} else {
|
||||||
|
setIncrementalCompiles(n => n + 1)
|
||||||
|
}
|
||||||
|
lastPdfUrl.current = pdfUrl
|
||||||
|
}, [clsiServerId, lastPdfUrl, pdfUrl, setIncrementalCompiles])
|
||||||
|
|
||||||
|
function submitFeedback(feedback = '') {
|
||||||
|
sendMB('faster-compiles-feedback', {
|
||||||
|
projectId,
|
||||||
|
server: clsiServerId?.includes('-c2d-') ? 'faster' : 'normal',
|
||||||
|
feedback,
|
||||||
|
pdfSize,
|
||||||
|
...deliveryLatencies,
|
||||||
|
})
|
||||||
|
setHasRatedProject(true)
|
||||||
|
setSayThanks(true)
|
||||||
|
window.setTimeout(() => {
|
||||||
|
setSayThanks(false)
|
||||||
|
}, SAY_THANKS_TIMEOUT)
|
||||||
|
}
|
||||||
|
|
||||||
|
function dismissFeedback() {
|
||||||
|
sendMB('faster-compiles-feedback-dismiss')
|
||||||
|
setDismiss(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
// Hide the feedback prompt in all these cases:
|
||||||
|
// - the initial compile (0), its always perceived as _slow_.
|
||||||
|
// - the first incremental compile (1), its always _faster_ than ^.
|
||||||
|
// - the user has dismissed the prompt
|
||||||
|
// - the user has rated compile speed already (say thanks if needed)
|
||||||
|
switch (true) {
|
||||||
|
case sayThanks:
|
||||||
|
return (
|
||||||
|
<Alert
|
||||||
|
bsStyle="info"
|
||||||
|
className="faster-compiles-feedback"
|
||||||
|
onClick={() => setSayThanks(false)}
|
||||||
|
>
|
||||||
|
{t('faster_compiles_feedback_thanks')}
|
||||||
|
</Alert>
|
||||||
|
)
|
||||||
|
case dismiss || hasRatedProject:
|
||||||
|
return null
|
||||||
|
case incrementalCompiles > 1:
|
||||||
|
return (
|
||||||
|
<Alert bsStyle="info" className="faster-compiles-feedback">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label={t('dismiss')}
|
||||||
|
className="btn-inline-link faster-compiles-feedback-dismiss"
|
||||||
|
onClick={dismissFeedback}
|
||||||
|
>
|
||||||
|
<Icon type="close" fw />
|
||||||
|
</button>
|
||||||
|
{t('faster_compiles_feedback_question')}
|
||||||
|
<div className="faster-compiles-feedback-options">
|
||||||
|
{['slower', 'same', 'faster'].map(feedback => (
|
||||||
|
<Button
|
||||||
|
bsStyle="default"
|
||||||
|
bsSize="xs"
|
||||||
|
className="faster-compiles-feedback-option"
|
||||||
|
onClick={() => submitFeedback(feedback)}
|
||||||
|
key={feedback}
|
||||||
|
>
|
||||||
|
{feedback === 'faster'
|
||||||
|
? t('faster_compiles_feedback_seems_faster')
|
||||||
|
: feedback === 'same'
|
||||||
|
? t('faster_compiles_feedback_seems_same')
|
||||||
|
: t('faster_compiles_feedback_seems_slower')}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Alert>
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function FasterCompilesFeedback() {
|
||||||
|
const { showFasterCompilesFeedbackUI } = useCompileContext()
|
||||||
|
|
||||||
|
if (!showFasterCompilesFeedbackUI) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return <FasterCompilesFeedbackContent />
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(FasterCompilesFeedback)
|
|
@ -9,7 +9,6 @@ import PDFJSWrapper from '../util/pdf-js-wrapper'
|
||||||
import withErrorBoundary from '../../../infrastructure/error-boundary'
|
import withErrorBoundary from '../../../infrastructure/error-boundary'
|
||||||
import ErrorBoundaryFallback from './error-boundary-fallback'
|
import ErrorBoundaryFallback from './error-boundary-fallback'
|
||||||
import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
|
import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
|
||||||
import getMeta from '../../../utils/meta'
|
|
||||||
import { captureException } from '../../../infrastructure/error-reporter'
|
import { captureException } from '../../../infrastructure/error-reporter'
|
||||||
|
|
||||||
function PdfJsViewer({ url }) {
|
function PdfJsViewer({ url }) {
|
||||||
|
@ -64,7 +63,7 @@ function PdfJsViewer({ url }) {
|
||||||
if (pdfJsWrapper) {
|
if (pdfJsWrapper) {
|
||||||
const handlePagesinit = () => {
|
const handlePagesinit = () => {
|
||||||
setInitialised(true)
|
setInitialised(true)
|
||||||
if (getMeta('ol-trackPdfDownload') && firstRenderDone) {
|
if (firstRenderDone) {
|
||||||
const visible = !document.hidden
|
const visible = !document.hidden
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
firstRenderDone({
|
firstRenderDone({
|
||||||
|
|
|
@ -5,6 +5,7 @@ import PdfViewer from './pdf-viewer'
|
||||||
import LoadingSpinner from '../../../shared/components/loading-spinner'
|
import LoadingSpinner from '../../../shared/components/loading-spinner'
|
||||||
import PdfHybridPreviewToolbar from './pdf-preview-hybrid-toolbar'
|
import PdfHybridPreviewToolbar from './pdf-preview-hybrid-toolbar'
|
||||||
import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
|
import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
|
||||||
|
import FasterCompilesFeedback from './faster-compiles-feedback'
|
||||||
|
|
||||||
function PdfPreviewPane() {
|
function PdfPreviewPane() {
|
||||||
const { pdfUrl } = useCompileContext()
|
const { pdfUrl } = useCompileContext()
|
||||||
|
@ -17,6 +18,7 @@ function PdfPreviewPane() {
|
||||||
<Suspense fallback={<LoadingPreview />}>
|
<Suspense fallback={<LoadingPreview />}>
|
||||||
<div className="pdf-viewer">
|
<div className="pdf-viewer">
|
||||||
<PdfViewer />
|
<PdfViewer />
|
||||||
|
<FasterCompilesFeedback />
|
||||||
</div>
|
</div>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
<PdfLogsViewer />
|
<PdfLogsViewer />
|
||||||
|
|
|
@ -22,6 +22,7 @@ export default class DocumentCompiler {
|
||||||
setCompiling,
|
setCompiling,
|
||||||
setData,
|
setData,
|
||||||
setFirstRenderDone,
|
setFirstRenderDone,
|
||||||
|
setDeliveryLatencies,
|
||||||
setError,
|
setError,
|
||||||
cleanupCompileResult,
|
cleanupCompileResult,
|
||||||
signal,
|
signal,
|
||||||
|
@ -33,6 +34,7 @@ export default class DocumentCompiler {
|
||||||
this.setCompiling = setCompiling
|
this.setCompiling = setCompiling
|
||||||
this.setData = setData
|
this.setData = setData
|
||||||
this.setFirstRenderDone = setFirstRenderDone
|
this.setFirstRenderDone = setFirstRenderDone
|
||||||
|
this.setDeliveryLatencies = setDeliveryLatencies
|
||||||
this.setError = setError
|
this.setError = setError
|
||||||
this.cleanupCompileResult = cleanupCompileResult
|
this.cleanupCompileResult = cleanupCompileResult
|
||||||
this.signal = signal
|
this.signal = signal
|
||||||
|
@ -100,8 +102,12 @@ export default class DocumentCompiler {
|
||||||
{ body, signal: this.signal }
|
{ body, signal: this.signal }
|
||||||
)
|
)
|
||||||
|
|
||||||
const compileTimeClientE2E = performance.now() - t0
|
const compileTimeClientE2E = Math.ceil(performance.now() - t0)
|
||||||
const { firstRenderDone } = trackPdfDownload(data, compileTimeClientE2E)
|
const { deliveryLatencies, firstRenderDone } = trackPdfDownload(
|
||||||
|
data,
|
||||||
|
compileTimeClientE2E
|
||||||
|
)
|
||||||
|
this.setDeliveryLatencies(() => deliveryLatencies)
|
||||||
this.setFirstRenderDone(() => firstRenderDone)
|
this.setFirstRenderDone(() => firstRenderDone)
|
||||||
|
|
||||||
// unset the error before it's set again later, so that components are recreated and events are tracked
|
// unset the error before it's set again later, so that components are recreated and events are tracked
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { v4 as uuid } from 'uuid'
|
import { v4 as uuid } from 'uuid'
|
||||||
import { sendMB } from '../../../infrastructure/event-tracking'
|
import { sendMB } from '../../../infrastructure/event-tracking'
|
||||||
|
import getMeta from '../../../utils/meta'
|
||||||
|
|
||||||
// VERSION should get incremented when making changes to caching behavior or
|
// VERSION should get incremented when making changes to caching behavior or
|
||||||
// adjusting metrics collection.
|
// adjusting metrics collection.
|
||||||
|
@ -20,15 +21,22 @@ export function trackPdfDownload(response, compileTimeClientE2E) {
|
||||||
|
|
||||||
const t0 = performance.now()
|
const t0 = performance.now()
|
||||||
let bandwidth = 0
|
let bandwidth = 0
|
||||||
|
const deliveryLatencies = {
|
||||||
|
compileTimeClientE2E,
|
||||||
|
compileTimeServerE2E: timings?.compileE2E,
|
||||||
|
}
|
||||||
|
|
||||||
function firstRenderDone({ timePDFFetched, timePDFRendered }) {
|
function firstRenderDone({ timePDFFetched, timePDFRendered }) {
|
||||||
const latencyFetch = timePDFFetched - t0
|
const latencyFetch = Math.ceil(timePDFFetched - t0)
|
||||||
|
deliveryLatencies.latencyFetch = latencyFetch
|
||||||
// The renderer does not yield in case the browser tab is hidden.
|
// The renderer does not yield in case the browser tab is hidden.
|
||||||
// It will yield when the browser tab is visible again.
|
// It will yield when the browser tab is visible again.
|
||||||
// This will skew our performance metrics for rendering!
|
// This will skew our performance metrics for rendering!
|
||||||
// We are omitting the render time in case we detect this state.
|
// We are omitting the render time in case we detect this state.
|
||||||
let latencyRender
|
let latencyRender
|
||||||
if (timePDFRendered) {
|
if (timePDFRendered) {
|
||||||
latencyRender = timePDFRendered - timePDFFetched
|
latencyRender = Math.ceil(timePDFRendered - timePDFFetched)
|
||||||
|
deliveryLatencies.latencyRender = latencyRender
|
||||||
}
|
}
|
||||||
done({ latencyFetch, latencyRender })
|
done({ latencyFetch, latencyRender })
|
||||||
}
|
}
|
||||||
|
@ -41,20 +49,23 @@ export function trackPdfDownload(response, compileTimeClientE2E) {
|
||||||
done = resolve
|
done = resolve
|
||||||
})
|
})
|
||||||
|
|
||||||
// Submit latency along with compile context.
|
if (getMeta('ol-trackPdfDownload')) {
|
||||||
onFirstRenderDone.then(({ latencyFetch, latencyRender }) => {
|
// Submit latency along with compile context.
|
||||||
submitCompileMetrics({
|
onFirstRenderDone.then(({ latencyFetch, latencyRender }) => {
|
||||||
latencyFetch,
|
submitCompileMetrics({
|
||||||
latencyRender,
|
latencyFetch,
|
||||||
compileTimeClientE2E,
|
latencyRender,
|
||||||
stats,
|
compileTimeClientE2E,
|
||||||
timings,
|
stats,
|
||||||
|
timings,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
// Submit bandwidth counter separate from compile context.
|
||||||
// Submit bandwidth counter separate from compile context.
|
submitPDFBandwidth({ pdfJsMetrics, serviceWorkerMetrics })
|
||||||
submitPDFBandwidth({ pdfJsMetrics, serviceWorkerMetrics })
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
deliveryLatencies,
|
||||||
firstRenderDone,
|
firstRenderDone,
|
||||||
updateConsumedBandwidth,
|
updateConsumedBandwidth,
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ export function handleOutputFiles(outputFiles, projectId, data) {
|
||||||
const result = {}
|
const result = {}
|
||||||
|
|
||||||
const outputFile = outputFiles.get('output.pdf')
|
const outputFile = outputFiles.get('output.pdf')
|
||||||
|
result.pdfSize = outputFile?.size
|
||||||
|
|
||||||
if (outputFile) {
|
if (outputFile) {
|
||||||
// build the URL for viewing the PDF in the preview UI
|
// build the URL for viewing the PDF in the preview UI
|
||||||
|
|
|
@ -26,6 +26,7 @@ export function DetachCompileProvider({ children }) {
|
||||||
clsiServerId: _clsiServerId,
|
clsiServerId: _clsiServerId,
|
||||||
codeCheckFailed: _codeCheckFailed,
|
codeCheckFailed: _codeCheckFailed,
|
||||||
compiling: _compiling,
|
compiling: _compiling,
|
||||||
|
deliveryLatencies: _deliveryLatencies,
|
||||||
draft: _draft,
|
draft: _draft,
|
||||||
error: _error,
|
error: _error,
|
||||||
fileList: _fileList,
|
fileList: _fileList,
|
||||||
|
@ -35,6 +36,7 @@ export function DetachCompileProvider({ children }) {
|
||||||
logEntries: _logEntries,
|
logEntries: _logEntries,
|
||||||
logEntryAnnotations: _logEntryAnnotations,
|
logEntryAnnotations: _logEntryAnnotations,
|
||||||
pdfDownloadUrl: _pdfDownloadUrl,
|
pdfDownloadUrl: _pdfDownloadUrl,
|
||||||
|
pdfSize: _pdfSize,
|
||||||
pdfUrl: _pdfUrl,
|
pdfUrl: _pdfUrl,
|
||||||
pdfViewer: _pdfViewer,
|
pdfViewer: _pdfViewer,
|
||||||
position: _position,
|
position: _position,
|
||||||
|
@ -51,6 +53,7 @@ export function DetachCompileProvider({ children }) {
|
||||||
setStopOnFirstError: _setStopOnFirstError,
|
setStopOnFirstError: _setStopOnFirstError,
|
||||||
setStopOnValidationError: _setStopOnValidationError,
|
setStopOnValidationError: _setStopOnValidationError,
|
||||||
showLogs: _showLogs,
|
showLogs: _showLogs,
|
||||||
|
showFasterCompilesFeedbackUI: _showFasterCompilesFeedbackUI,
|
||||||
stopOnFirstError: _stopOnFirstError,
|
stopOnFirstError: _stopOnFirstError,
|
||||||
stopOnValidationError: _stopOnValidationError,
|
stopOnValidationError: _stopOnValidationError,
|
||||||
stoppedOnFirstError: _stoppedOnFirstError,
|
stoppedOnFirstError: _stoppedOnFirstError,
|
||||||
|
@ -102,6 +105,12 @@ export function DetachCompileProvider({ children }) {
|
||||||
'detacher',
|
'detacher',
|
||||||
'detached'
|
'detached'
|
||||||
)
|
)
|
||||||
|
const [deliveryLatencies] = useDetachStateWatcher(
|
||||||
|
'deliveryLatencies',
|
||||||
|
_deliveryLatencies,
|
||||||
|
'detacher',
|
||||||
|
'detached'
|
||||||
|
)
|
||||||
const [draft] = useDetachStateWatcher('draft', _draft, 'detacher', 'detached')
|
const [draft] = useDetachStateWatcher('draft', _draft, 'detacher', 'detached')
|
||||||
const [error] = useDetachStateWatcher('error', _error, 'detacher', 'detached')
|
const [error] = useDetachStateWatcher('error', _error, 'detacher', 'detached')
|
||||||
const [fileList] = useDetachStateWatcher(
|
const [fileList] = useDetachStateWatcher(
|
||||||
|
@ -146,6 +155,12 @@ export function DetachCompileProvider({ children }) {
|
||||||
'detacher',
|
'detacher',
|
||||||
'detached'
|
'detached'
|
||||||
)
|
)
|
||||||
|
const [pdfSize] = useDetachStateWatcher(
|
||||||
|
'pdfSize',
|
||||||
|
_pdfSize,
|
||||||
|
'detacher',
|
||||||
|
'detached'
|
||||||
|
)
|
||||||
const [pdfUrl] = useDetachStateWatcher(
|
const [pdfUrl] = useDetachStateWatcher(
|
||||||
'pdfUrl',
|
'pdfUrl',
|
||||||
_pdfUrl,
|
_pdfUrl,
|
||||||
|
@ -176,6 +191,12 @@ export function DetachCompileProvider({ children }) {
|
||||||
'detacher',
|
'detacher',
|
||||||
'detached'
|
'detached'
|
||||||
)
|
)
|
||||||
|
const [showFasterCompilesFeedbackUI] = useDetachStateWatcher(
|
||||||
|
'showFasterCompilesFeedbackUI',
|
||||||
|
_showFasterCompilesFeedbackUI,
|
||||||
|
'detacher',
|
||||||
|
'detached'
|
||||||
|
)
|
||||||
const [stopOnFirstError] = useDetachStateWatcher(
|
const [stopOnFirstError] = useDetachStateWatcher(
|
||||||
'stopOnFirstError',
|
'stopOnFirstError',
|
||||||
_stopOnFirstError,
|
_stopOnFirstError,
|
||||||
|
@ -331,6 +352,7 @@ export function DetachCompileProvider({ children }) {
|
||||||
clsiServerId,
|
clsiServerId,
|
||||||
codeCheckFailed,
|
codeCheckFailed,
|
||||||
compiling,
|
compiling,
|
||||||
|
deliveryLatencies,
|
||||||
draft,
|
draft,
|
||||||
error,
|
error,
|
||||||
fileList,
|
fileList,
|
||||||
|
@ -340,6 +362,7 @@ export function DetachCompileProvider({ children }) {
|
||||||
logEntryAnnotations,
|
logEntryAnnotations,
|
||||||
logEntries,
|
logEntries,
|
||||||
pdfDownloadUrl,
|
pdfDownloadUrl,
|
||||||
|
pdfSize,
|
||||||
pdfUrl,
|
pdfUrl,
|
||||||
pdfViewer,
|
pdfViewer,
|
||||||
position,
|
position,
|
||||||
|
@ -358,6 +381,7 @@ export function DetachCompileProvider({ children }) {
|
||||||
setStopOnFirstError,
|
setStopOnFirstError,
|
||||||
setStopOnValidationError,
|
setStopOnValidationError,
|
||||||
showLogs,
|
showLogs,
|
||||||
|
showFasterCompilesFeedbackUI,
|
||||||
startCompile,
|
startCompile,
|
||||||
stopCompile,
|
stopCompile,
|
||||||
stopOnFirstError,
|
stopOnFirstError,
|
||||||
|
@ -377,6 +401,7 @@ export function DetachCompileProvider({ children }) {
|
||||||
clsiServerId,
|
clsiServerId,
|
||||||
codeCheckFailed,
|
codeCheckFailed,
|
||||||
compiling,
|
compiling,
|
||||||
|
deliveryLatencies,
|
||||||
draft,
|
draft,
|
||||||
error,
|
error,
|
||||||
fileList,
|
fileList,
|
||||||
|
@ -386,6 +411,7 @@ export function DetachCompileProvider({ children }) {
|
||||||
logEntryAnnotations,
|
logEntryAnnotations,
|
||||||
logEntries,
|
logEntries,
|
||||||
pdfDownloadUrl,
|
pdfDownloadUrl,
|
||||||
|
pdfSize,
|
||||||
pdfUrl,
|
pdfUrl,
|
||||||
pdfViewer,
|
pdfViewer,
|
||||||
position,
|
position,
|
||||||
|
@ -404,6 +430,7 @@ export function DetachCompileProvider({ children }) {
|
||||||
setStopOnFirstError,
|
setStopOnFirstError,
|
||||||
setStopOnValidationError,
|
setStopOnValidationError,
|
||||||
showLogs,
|
showLogs,
|
||||||
|
showFasterCompilesFeedbackUI,
|
||||||
startCompile,
|
startCompile,
|
||||||
stopCompile,
|
stopCompile,
|
||||||
stopOnFirstError,
|
stopOnFirstError,
|
||||||
|
|
|
@ -37,6 +37,7 @@ export const CompileContextPropTypes = {
|
||||||
clsiServerId: PropTypes.string,
|
clsiServerId: PropTypes.string,
|
||||||
codeCheckFailed: PropTypes.bool.isRequired,
|
codeCheckFailed: PropTypes.bool.isRequired,
|
||||||
compiling: PropTypes.bool.isRequired,
|
compiling: PropTypes.bool.isRequired,
|
||||||
|
deliveryLatencies: PropTypes.object.isRequired,
|
||||||
draft: PropTypes.bool.isRequired,
|
draft: PropTypes.bool.isRequired,
|
||||||
error: PropTypes.string,
|
error: PropTypes.string,
|
||||||
fileList: PropTypes.object,
|
fileList: PropTypes.object,
|
||||||
|
@ -45,6 +46,7 @@ export const CompileContextPropTypes = {
|
||||||
logEntries: PropTypes.object,
|
logEntries: PropTypes.object,
|
||||||
logEntryAnnotations: PropTypes.object,
|
logEntryAnnotations: PropTypes.object,
|
||||||
pdfDownloadUrl: PropTypes.string,
|
pdfDownloadUrl: PropTypes.string,
|
||||||
|
pdfSize: PropTypes.number,
|
||||||
pdfUrl: PropTypes.string,
|
pdfUrl: PropTypes.string,
|
||||||
pdfViewer: PropTypes.string,
|
pdfViewer: PropTypes.string,
|
||||||
position: PropTypes.object,
|
position: PropTypes.object,
|
||||||
|
@ -60,6 +62,7 @@ export const CompileContextPropTypes = {
|
||||||
setStopOnFirstError: PropTypes.func.isRequired,
|
setStopOnFirstError: PropTypes.func.isRequired,
|
||||||
setStopOnValidationError: PropTypes.func.isRequired,
|
setStopOnValidationError: PropTypes.func.isRequired,
|
||||||
showLogs: PropTypes.bool.isRequired,
|
showLogs: PropTypes.bool.isRequired,
|
||||||
|
showFasterCompilesFeedbackUI: PropTypes.bool.isRequired,
|
||||||
stopOnFirstError: PropTypes.bool.isRequired,
|
stopOnFirstError: PropTypes.bool.isRequired,
|
||||||
stopOnValidationError: PropTypes.bool.isRequired,
|
stopOnValidationError: PropTypes.bool.isRequired,
|
||||||
stoppedOnFirstError: PropTypes.bool.isRequired,
|
stoppedOnFirstError: PropTypes.bool.isRequired,
|
||||||
|
@ -100,6 +103,8 @@ export function LocalCompileProvider({ children }) {
|
||||||
// the URL for loading the PDF in the preview pane
|
// the URL for loading the PDF in the preview pane
|
||||||
const [pdfUrl, setPdfUrl] = useScopeValueSetterOnly('pdf.url')
|
const [pdfUrl, setPdfUrl] = useScopeValueSetterOnly('pdf.url')
|
||||||
|
|
||||||
|
const [pdfSize, setPdfSize] = useState(0)
|
||||||
|
|
||||||
// the project is considered to be "uncompiled" if a doc has changed since the last compile started
|
// the project is considered to be "uncompiled" if a doc has changed since the last compile started
|
||||||
const [uncompiled, setUncompiled] = useScopeValue('pdf.uncompiled')
|
const [uncompiled, setUncompiled] = useScopeValue('pdf.uncompiled')
|
||||||
|
|
||||||
|
@ -112,6 +117,9 @@ export function LocalCompileProvider({ children }) {
|
||||||
// callback to be invoked for PdfJsMetrics
|
// callback to be invoked for PdfJsMetrics
|
||||||
const [firstRenderDone, setFirstRenderDone] = useState()
|
const [firstRenderDone, setFirstRenderDone] = useState()
|
||||||
|
|
||||||
|
// latencies of compile/pdf download/rendering
|
||||||
|
const [deliveryLatencies, setDeliveryLatencies] = useState({})
|
||||||
|
|
||||||
// whether the project has been compiled yet
|
// whether the project has been compiled yet
|
||||||
const [compiledOnce, setCompiledOnce] = useState(false)
|
const [compiledOnce, setCompiledOnce] = useState(false)
|
||||||
|
|
||||||
|
@ -121,6 +129,10 @@ export function LocalCompileProvider({ children }) {
|
||||||
// whether the logs should be visible
|
// whether the logs should be visible
|
||||||
const [showLogs, setShowLogs] = useState(false)
|
const [showLogs, setShowLogs] = useState(false)
|
||||||
|
|
||||||
|
// whether the faster compiles feedback UI should be displayed
|
||||||
|
const [showFasterCompilesFeedbackUI, setShowFasterCompilesFeedbackUI] =
|
||||||
|
useState(false)
|
||||||
|
|
||||||
// whether the compile dropdown arrow should be animated
|
// whether the compile dropdown arrow should be animated
|
||||||
const [animateCompileDropdownArrow, setAnimateCompileDropdownArrow] =
|
const [animateCompileDropdownArrow, setAnimateCompileDropdownArrow] =
|
||||||
useState(false)
|
useState(false)
|
||||||
|
@ -215,6 +227,7 @@ export function LocalCompileProvider({ children }) {
|
||||||
setCompiling,
|
setCompiling,
|
||||||
setData,
|
setData,
|
||||||
setFirstRenderDone,
|
setFirstRenderDone,
|
||||||
|
setDeliveryLatencies,
|
||||||
setError,
|
setError,
|
||||||
cleanupCompileResult,
|
cleanupCompileResult,
|
||||||
compilingRef,
|
compilingRef,
|
||||||
|
@ -260,6 +273,9 @@ export function LocalCompileProvider({ children }) {
|
||||||
if (data.clsiServerId) {
|
if (data.clsiServerId) {
|
||||||
setClsiServerId(data.clsiServerId) // set in scope, for PdfSynctexController
|
setClsiServerId(data.clsiServerId) // set in scope, for PdfSynctexController
|
||||||
}
|
}
|
||||||
|
setShowFasterCompilesFeedbackUI(
|
||||||
|
Boolean(data.showFasterCompilesFeedbackUI)
|
||||||
|
)
|
||||||
|
|
||||||
if (data.outputFiles) {
|
if (data.outputFiles) {
|
||||||
const outputFiles = new Map()
|
const outputFiles = new Map()
|
||||||
|
@ -272,6 +288,7 @@ export function LocalCompileProvider({ children }) {
|
||||||
const result = handleOutputFiles(outputFiles, projectId, data)
|
const result = handleOutputFiles(outputFiles, projectId, data)
|
||||||
if (data.status === 'success') {
|
if (data.status === 'success') {
|
||||||
setPdfDownloadUrl(result.pdfDownloadUrl)
|
setPdfDownloadUrl(result.pdfDownloadUrl)
|
||||||
|
setPdfSize(result.pdfSize)
|
||||||
setPdfUrl(result.pdfUrl)
|
setPdfUrl(result.pdfUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,6 +406,7 @@ export function LocalCompileProvider({ children }) {
|
||||||
setLogEntries,
|
setLogEntries,
|
||||||
setLogEntryAnnotations,
|
setLogEntryAnnotations,
|
||||||
setPdfDownloadUrl,
|
setPdfDownloadUrl,
|
||||||
|
setPdfSize,
|
||||||
setPdfUrl,
|
setPdfUrl,
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -479,6 +497,7 @@ export function LocalCompileProvider({ children }) {
|
||||||
clsiServerId,
|
clsiServerId,
|
||||||
codeCheckFailed,
|
codeCheckFailed,
|
||||||
compiling,
|
compiling,
|
||||||
|
deliveryLatencies,
|
||||||
draft,
|
draft,
|
||||||
error,
|
error,
|
||||||
fileList,
|
fileList,
|
||||||
|
@ -488,6 +507,7 @@ export function LocalCompileProvider({ children }) {
|
||||||
logEntryAnnotations,
|
logEntryAnnotations,
|
||||||
logEntries,
|
logEntries,
|
||||||
pdfDownloadUrl,
|
pdfDownloadUrl,
|
||||||
|
pdfSize,
|
||||||
pdfUrl,
|
pdfUrl,
|
||||||
pdfViewer,
|
pdfViewer,
|
||||||
position,
|
position,
|
||||||
|
@ -506,6 +526,7 @@ export function LocalCompileProvider({ children }) {
|
||||||
setStopOnFirstError,
|
setStopOnFirstError,
|
||||||
setStopOnValidationError,
|
setStopOnValidationError,
|
||||||
showLogs,
|
showLogs,
|
||||||
|
showFasterCompilesFeedbackUI,
|
||||||
startCompile,
|
startCompile,
|
||||||
stopCompile,
|
stopCompile,
|
||||||
stopOnFirstError,
|
stopOnFirstError,
|
||||||
|
@ -525,6 +546,7 @@ export function LocalCompileProvider({ children }) {
|
||||||
clsiServerId,
|
clsiServerId,
|
||||||
codeCheckFailed,
|
codeCheckFailed,
|
||||||
compiling,
|
compiling,
|
||||||
|
deliveryLatencies,
|
||||||
draft,
|
draft,
|
||||||
error,
|
error,
|
||||||
fileList,
|
fileList,
|
||||||
|
@ -535,6 +557,7 @@ export function LocalCompileProvider({ children }) {
|
||||||
logEntryAnnotations,
|
logEntryAnnotations,
|
||||||
position,
|
position,
|
||||||
pdfDownloadUrl,
|
pdfDownloadUrl,
|
||||||
|
pdfSize,
|
||||||
pdfUrl,
|
pdfUrl,
|
||||||
pdfViewer,
|
pdfViewer,
|
||||||
rawLog,
|
rawLog,
|
||||||
|
@ -549,6 +572,7 @@ export function LocalCompileProvider({ children }) {
|
||||||
setStopOnFirstError,
|
setStopOnFirstError,
|
||||||
setStopOnValidationError,
|
setStopOnValidationError,
|
||||||
showLogs,
|
showLogs,
|
||||||
|
showFasterCompilesFeedbackUI,
|
||||||
startCompile,
|
startCompile,
|
||||||
stopCompile,
|
stopCompile,
|
||||||
stopOnFirstError,
|
stopOnFirstError,
|
||||||
|
|
|
@ -126,6 +126,34 @@
|
||||||
padding: @line-height-computed 0;
|
padding: @line-height-computed 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.faster-compiles-feedback {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0.5rem; // scrollbar
|
||||||
|
margin: 1rem;
|
||||||
|
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
margin: 0 0 0 10px;
|
||||||
|
}
|
||||||
|
.faster-compiles-feedback-options {
|
||||||
|
display: inline;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.faster-compiles-feedback-option {
|
||||||
|
background: #1d4c82;
|
||||||
|
}
|
||||||
|
.faster-compiles-feedback-dismiss {
|
||||||
|
border: 0;
|
||||||
|
margin: 0 0 0 5px;
|
||||||
|
color: #1d4c82;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.toolbar-editor {
|
.toolbar-editor {
|
||||||
height: @editor-toolbar-height;
|
height: @editor-toolbar-height;
|
||||||
background-color: @editor-toolbar-bg;
|
background-color: @editor-toolbar-bg;
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
{
|
{
|
||||||
|
"faster_compiles_feedback_question": "Was this compile different than usual?",
|
||||||
|
"faster_compiles_feedback_seems_faster": "Faster",
|
||||||
|
"faster_compiles_feedback_seems_same": "Same",
|
||||||
|
"faster_compiles_feedback_seems_slower": "Slower",
|
||||||
|
"faster_compiles_feedback_thanks": "Thanks for the feedback!",
|
||||||
"generic_linked_file_compile_error": "This project’s output files are not available because it failed to compile. Please open the project to see the compilation error details.",
|
"generic_linked_file_compile_error": "This project’s output files are not available because it failed to compile. Please open the project to see the compilation error details.",
|
||||||
"chat_error": "Could not load chat messages, please try again.",
|
"chat_error": "Could not load chat messages, please try again.",
|
||||||
"reconnect": "Try again",
|
"reconnect": "Try again",
|
||||||
|
|
|
@ -113,6 +113,7 @@ describe('CompileController', function () {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
pdfDownloadDomain: 'https://compiles.overleaf.test',
|
pdfDownloadDomain: 'https://compiles.overleaf.test',
|
||||||
|
showFasterCompilesFeedbackUI: false,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -154,6 +155,7 @@ describe('CompileController', function () {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
pdfDownloadDomain: 'https://compiles.overleaf.test/zone/b',
|
pdfDownloadDomain: 'https://compiles.overleaf.test/zone/b',
|
||||||
|
showFasterCompilesFeedbackUI: false,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -191,6 +193,7 @@ describe('CompileController', function () {
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
status: this.status,
|
status: this.status,
|
||||||
outputFiles: this.outputFiles,
|
outputFiles: this.outputFiles,
|
||||||
|
showFasterCompilesFeedbackUI: false,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue