diff --git a/services/web/app/src/Features/Compile/CompileController.js b/services/web/app/src/Features/Compile/CompileController.js
index 5d6f39ade9..923ff99550 100644
--- a/services/web/app/src/Features/Compile/CompileController.js
+++ b/services/web/app/src/Features/Compile/CompileController.js
@@ -88,7 +88,9 @@ module.exports = CompileController = {
if (pdfDownloadDomain && outputUrlPrefix) {
pdfDownloadDomain += outputUrlPrefix
}
+ let showFasterCompilesFeedbackUI = false
if (limits?.emitCompileResultEvent) {
+ showFasterCompilesFeedbackUI = true
AnalyticsManager.recordEventForSession(
req.session,
'compile-result-backend',
@@ -111,6 +113,7 @@ module.exports = CompileController = {
stats,
timings,
pdfDownloadDomain,
+ showFasterCompilesFeedbackUI,
})
}
)
diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json
index dd263ff7fe..c3298afefc 100644
--- a/services/web/frontend/extracted-translations.json
+++ b/services/web/frontend/extracted-translations.json
@@ -125,6 +125,11 @@
"expand": "",
"export_project_to_github": "",
"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_in_this_location": "",
"file_name": "",
diff --git a/services/web/frontend/js/features/pdf-preview/components/faster-compiles-feedback.tsx b/services/web/frontend/js/features/pdf-preview/components/faster-compiles-feedback.tsx
new file mode 100644
index 0000000000..55aace5445
--- /dev/null
+++ b/services/web/frontend/js/features/pdf-preview/components/faster-compiles-feedback.tsx
@@ -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 (
+ setSayThanks(false)}
+ >
+ {t('faster_compiles_feedback_thanks')}
+
+ )
+ case dismiss || hasRatedProject:
+ return null
+ case incrementalCompiles > 1:
+ return (
+
+
+ {t('faster_compiles_feedback_question')}
+
+ {['slower', 'same', 'faster'].map(feedback => (
+
+ ))}
+
+
+ )
+ default:
+ return null
+ }
+}
+
+function FasterCompilesFeedback() {
+ const { showFasterCompilesFeedbackUI } = useCompileContext()
+
+ if (!showFasterCompilesFeedbackUI) {
+ return null
+ }
+ return
+}
+
+export default memo(FasterCompilesFeedback)
diff --git a/services/web/frontend/js/features/pdf-preview/components/pdf-js-viewer.js b/services/web/frontend/js/features/pdf-preview/components/pdf-js-viewer.js
index 5961f3dc7e..dbb008bcc8 100644
--- a/services/web/frontend/js/features/pdf-preview/components/pdf-js-viewer.js
+++ b/services/web/frontend/js/features/pdf-preview/components/pdf-js-viewer.js
@@ -9,7 +9,6 @@ import PDFJSWrapper from '../util/pdf-js-wrapper'
import withErrorBoundary from '../../../infrastructure/error-boundary'
import ErrorBoundaryFallback from './error-boundary-fallback'
import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
-import getMeta from '../../../utils/meta'
import { captureException } from '../../../infrastructure/error-reporter'
function PdfJsViewer({ url }) {
@@ -64,7 +63,7 @@ function PdfJsViewer({ url }) {
if (pdfJsWrapper) {
const handlePagesinit = () => {
setInitialised(true)
- if (getMeta('ol-trackPdfDownload') && firstRenderDone) {
+ if (firstRenderDone) {
const visible = !document.hidden
if (!visible) {
firstRenderDone({
diff --git a/services/web/frontend/js/features/pdf-preview/components/pdf-preview-pane.js b/services/web/frontend/js/features/pdf-preview/components/pdf-preview-pane.js
index cf5e7d880a..9ebfe92d0c 100644
--- a/services/web/frontend/js/features/pdf-preview/components/pdf-preview-pane.js
+++ b/services/web/frontend/js/features/pdf-preview/components/pdf-preview-pane.js
@@ -5,6 +5,7 @@ import PdfViewer from './pdf-viewer'
import LoadingSpinner from '../../../shared/components/loading-spinner'
import PdfHybridPreviewToolbar from './pdf-preview-hybrid-toolbar'
import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
+import FasterCompilesFeedback from './faster-compiles-feedback'
function PdfPreviewPane() {
const { pdfUrl } = useCompileContext()
@@ -17,6 +18,7 @@ function PdfPreviewPane() {
}>
diff --git a/services/web/frontend/js/features/pdf-preview/util/compiler.js b/services/web/frontend/js/features/pdf-preview/util/compiler.js
index 00441fc5b9..821c7040f9 100644
--- a/services/web/frontend/js/features/pdf-preview/util/compiler.js
+++ b/services/web/frontend/js/features/pdf-preview/util/compiler.js
@@ -22,6 +22,7 @@ export default class DocumentCompiler {
setCompiling,
setData,
setFirstRenderDone,
+ setDeliveryLatencies,
setError,
cleanupCompileResult,
signal,
@@ -33,6 +34,7 @@ export default class DocumentCompiler {
this.setCompiling = setCompiling
this.setData = setData
this.setFirstRenderDone = setFirstRenderDone
+ this.setDeliveryLatencies = setDeliveryLatencies
this.setError = setError
this.cleanupCompileResult = cleanupCompileResult
this.signal = signal
@@ -100,8 +102,12 @@ export default class DocumentCompiler {
{ body, signal: this.signal }
)
- const compileTimeClientE2E = performance.now() - t0
- const { firstRenderDone } = trackPdfDownload(data, compileTimeClientE2E)
+ const compileTimeClientE2E = Math.ceil(performance.now() - t0)
+ const { deliveryLatencies, firstRenderDone } = trackPdfDownload(
+ data,
+ compileTimeClientE2E
+ )
+ this.setDeliveryLatencies(() => deliveryLatencies)
this.setFirstRenderDone(() => firstRenderDone)
// unset the error before it's set again later, so that components are recreated and events are tracked
diff --git a/services/web/frontend/js/features/pdf-preview/util/metrics.js b/services/web/frontend/js/features/pdf-preview/util/metrics.js
index 12b7067d2c..e2b319dd51 100644
--- a/services/web/frontend/js/features/pdf-preview/util/metrics.js
+++ b/services/web/frontend/js/features/pdf-preview/util/metrics.js
@@ -1,5 +1,6 @@
import { v4 as uuid } from 'uuid'
import { sendMB } from '../../../infrastructure/event-tracking'
+import getMeta from '../../../utils/meta'
// VERSION should get incremented when making changes to caching behavior or
// adjusting metrics collection.
@@ -20,15 +21,22 @@ export function trackPdfDownload(response, compileTimeClientE2E) {
const t0 = performance.now()
let bandwidth = 0
+ const deliveryLatencies = {
+ compileTimeClientE2E,
+ compileTimeServerE2E: timings?.compileE2E,
+ }
+
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.
// It will yield when the browser tab is visible again.
// This will skew our performance metrics for rendering!
// We are omitting the render time in case we detect this state.
let latencyRender
if (timePDFRendered) {
- latencyRender = timePDFRendered - timePDFFetched
+ latencyRender = Math.ceil(timePDFRendered - timePDFFetched)
+ deliveryLatencies.latencyRender = latencyRender
}
done({ latencyFetch, latencyRender })
}
@@ -41,20 +49,23 @@ export function trackPdfDownload(response, compileTimeClientE2E) {
done = resolve
})
- // Submit latency along with compile context.
- onFirstRenderDone.then(({ latencyFetch, latencyRender }) => {
- submitCompileMetrics({
- latencyFetch,
- latencyRender,
- compileTimeClientE2E,
- stats,
- timings,
+ if (getMeta('ol-trackPdfDownload')) {
+ // Submit latency along with compile context.
+ onFirstRenderDone.then(({ latencyFetch, latencyRender }) => {
+ submitCompileMetrics({
+ latencyFetch,
+ latencyRender,
+ compileTimeClientE2E,
+ stats,
+ timings,
+ })
})
- })
- // Submit bandwidth counter separate from compile context.
- submitPDFBandwidth({ pdfJsMetrics, serviceWorkerMetrics })
+ // Submit bandwidth counter separate from compile context.
+ submitPDFBandwidth({ pdfJsMetrics, serviceWorkerMetrics })
+ }
return {
+ deliveryLatencies,
firstRenderDone,
updateConsumedBandwidth,
}
diff --git a/services/web/frontend/js/features/pdf-preview/util/output-files.js b/services/web/frontend/js/features/pdf-preview/util/output-files.js
index a48317c1ed..3e214f2465 100644
--- a/services/web/frontend/js/features/pdf-preview/util/output-files.js
+++ b/services/web/frontend/js/features/pdf-preview/util/output-files.js
@@ -9,6 +9,7 @@ export function handleOutputFiles(outputFiles, projectId, data) {
const result = {}
const outputFile = outputFiles.get('output.pdf')
+ result.pdfSize = outputFile?.size
if (outputFile) {
// build the URL for viewing the PDF in the preview UI
diff --git a/services/web/frontend/js/shared/context/detach-compile-context.js b/services/web/frontend/js/shared/context/detach-compile-context.js
index c66fda8b6b..ebdac2c93f 100644
--- a/services/web/frontend/js/shared/context/detach-compile-context.js
+++ b/services/web/frontend/js/shared/context/detach-compile-context.js
@@ -26,6 +26,7 @@ export function DetachCompileProvider({ children }) {
clsiServerId: _clsiServerId,
codeCheckFailed: _codeCheckFailed,
compiling: _compiling,
+ deliveryLatencies: _deliveryLatencies,
draft: _draft,
error: _error,
fileList: _fileList,
@@ -35,6 +36,7 @@ export function DetachCompileProvider({ children }) {
logEntries: _logEntries,
logEntryAnnotations: _logEntryAnnotations,
pdfDownloadUrl: _pdfDownloadUrl,
+ pdfSize: _pdfSize,
pdfUrl: _pdfUrl,
pdfViewer: _pdfViewer,
position: _position,
@@ -51,6 +53,7 @@ export function DetachCompileProvider({ children }) {
setStopOnFirstError: _setStopOnFirstError,
setStopOnValidationError: _setStopOnValidationError,
showLogs: _showLogs,
+ showFasterCompilesFeedbackUI: _showFasterCompilesFeedbackUI,
stopOnFirstError: _stopOnFirstError,
stopOnValidationError: _stopOnValidationError,
stoppedOnFirstError: _stoppedOnFirstError,
@@ -102,6 +105,12 @@ export function DetachCompileProvider({ children }) {
'detacher',
'detached'
)
+ const [deliveryLatencies] = useDetachStateWatcher(
+ 'deliveryLatencies',
+ _deliveryLatencies,
+ 'detacher',
+ 'detached'
+ )
const [draft] = useDetachStateWatcher('draft', _draft, 'detacher', 'detached')
const [error] = useDetachStateWatcher('error', _error, 'detacher', 'detached')
const [fileList] = useDetachStateWatcher(
@@ -146,6 +155,12 @@ export function DetachCompileProvider({ children }) {
'detacher',
'detached'
)
+ const [pdfSize] = useDetachStateWatcher(
+ 'pdfSize',
+ _pdfSize,
+ 'detacher',
+ 'detached'
+ )
const [pdfUrl] = useDetachStateWatcher(
'pdfUrl',
_pdfUrl,
@@ -176,6 +191,12 @@ export function DetachCompileProvider({ children }) {
'detacher',
'detached'
)
+ const [showFasterCompilesFeedbackUI] = useDetachStateWatcher(
+ 'showFasterCompilesFeedbackUI',
+ _showFasterCompilesFeedbackUI,
+ 'detacher',
+ 'detached'
+ )
const [stopOnFirstError] = useDetachStateWatcher(
'stopOnFirstError',
_stopOnFirstError,
@@ -331,6 +352,7 @@ export function DetachCompileProvider({ children }) {
clsiServerId,
codeCheckFailed,
compiling,
+ deliveryLatencies,
draft,
error,
fileList,
@@ -340,6 +362,7 @@ export function DetachCompileProvider({ children }) {
logEntryAnnotations,
logEntries,
pdfDownloadUrl,
+ pdfSize,
pdfUrl,
pdfViewer,
position,
@@ -358,6 +381,7 @@ export function DetachCompileProvider({ children }) {
setStopOnFirstError,
setStopOnValidationError,
showLogs,
+ showFasterCompilesFeedbackUI,
startCompile,
stopCompile,
stopOnFirstError,
@@ -377,6 +401,7 @@ export function DetachCompileProvider({ children }) {
clsiServerId,
codeCheckFailed,
compiling,
+ deliveryLatencies,
draft,
error,
fileList,
@@ -386,6 +411,7 @@ export function DetachCompileProvider({ children }) {
logEntryAnnotations,
logEntries,
pdfDownloadUrl,
+ pdfSize,
pdfUrl,
pdfViewer,
position,
@@ -404,6 +430,7 @@ export function DetachCompileProvider({ children }) {
setStopOnFirstError,
setStopOnValidationError,
showLogs,
+ showFasterCompilesFeedbackUI,
startCompile,
stopCompile,
stopOnFirstError,
diff --git a/services/web/frontend/js/shared/context/local-compile-context.js b/services/web/frontend/js/shared/context/local-compile-context.js
index 7534ca237e..7c7c8f2058 100644
--- a/services/web/frontend/js/shared/context/local-compile-context.js
+++ b/services/web/frontend/js/shared/context/local-compile-context.js
@@ -37,6 +37,7 @@ export const CompileContextPropTypes = {
clsiServerId: PropTypes.string,
codeCheckFailed: PropTypes.bool.isRequired,
compiling: PropTypes.bool.isRequired,
+ deliveryLatencies: PropTypes.object.isRequired,
draft: PropTypes.bool.isRequired,
error: PropTypes.string,
fileList: PropTypes.object,
@@ -45,6 +46,7 @@ export const CompileContextPropTypes = {
logEntries: PropTypes.object,
logEntryAnnotations: PropTypes.object,
pdfDownloadUrl: PropTypes.string,
+ pdfSize: PropTypes.number,
pdfUrl: PropTypes.string,
pdfViewer: PropTypes.string,
position: PropTypes.object,
@@ -60,6 +62,7 @@ export const CompileContextPropTypes = {
setStopOnFirstError: PropTypes.func.isRequired,
setStopOnValidationError: PropTypes.func.isRequired,
showLogs: PropTypes.bool.isRequired,
+ showFasterCompilesFeedbackUI: PropTypes.bool.isRequired,
stopOnFirstError: PropTypes.bool.isRequired,
stopOnValidationError: 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
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
const [uncompiled, setUncompiled] = useScopeValue('pdf.uncompiled')
@@ -112,6 +117,9 @@ export function LocalCompileProvider({ children }) {
// callback to be invoked for PdfJsMetrics
const [firstRenderDone, setFirstRenderDone] = useState()
+ // latencies of compile/pdf download/rendering
+ const [deliveryLatencies, setDeliveryLatencies] = useState({})
+
// whether the project has been compiled yet
const [compiledOnce, setCompiledOnce] = useState(false)
@@ -121,6 +129,10 @@ export function LocalCompileProvider({ children }) {
// whether the logs should be visible
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
const [animateCompileDropdownArrow, setAnimateCompileDropdownArrow] =
useState(false)
@@ -215,6 +227,7 @@ export function LocalCompileProvider({ children }) {
setCompiling,
setData,
setFirstRenderDone,
+ setDeliveryLatencies,
setError,
cleanupCompileResult,
compilingRef,
@@ -260,6 +273,9 @@ export function LocalCompileProvider({ children }) {
if (data.clsiServerId) {
setClsiServerId(data.clsiServerId) // set in scope, for PdfSynctexController
}
+ setShowFasterCompilesFeedbackUI(
+ Boolean(data.showFasterCompilesFeedbackUI)
+ )
if (data.outputFiles) {
const outputFiles = new Map()
@@ -272,6 +288,7 @@ export function LocalCompileProvider({ children }) {
const result = handleOutputFiles(outputFiles, projectId, data)
if (data.status === 'success') {
setPdfDownloadUrl(result.pdfDownloadUrl)
+ setPdfSize(result.pdfSize)
setPdfUrl(result.pdfUrl)
}
@@ -389,6 +406,7 @@ export function LocalCompileProvider({ children }) {
setLogEntries,
setLogEntryAnnotations,
setPdfDownloadUrl,
+ setPdfSize,
setPdfUrl,
])
@@ -479,6 +497,7 @@ export function LocalCompileProvider({ children }) {
clsiServerId,
codeCheckFailed,
compiling,
+ deliveryLatencies,
draft,
error,
fileList,
@@ -488,6 +507,7 @@ export function LocalCompileProvider({ children }) {
logEntryAnnotations,
logEntries,
pdfDownloadUrl,
+ pdfSize,
pdfUrl,
pdfViewer,
position,
@@ -506,6 +526,7 @@ export function LocalCompileProvider({ children }) {
setStopOnFirstError,
setStopOnValidationError,
showLogs,
+ showFasterCompilesFeedbackUI,
startCompile,
stopCompile,
stopOnFirstError,
@@ -525,6 +546,7 @@ export function LocalCompileProvider({ children }) {
clsiServerId,
codeCheckFailed,
compiling,
+ deliveryLatencies,
draft,
error,
fileList,
@@ -535,6 +557,7 @@ export function LocalCompileProvider({ children }) {
logEntryAnnotations,
position,
pdfDownloadUrl,
+ pdfSize,
pdfUrl,
pdfViewer,
rawLog,
@@ -549,6 +572,7 @@ export function LocalCompileProvider({ children }) {
setStopOnFirstError,
setStopOnValidationError,
showLogs,
+ showFasterCompilesFeedbackUI,
startCompile,
stopCompile,
stopOnFirstError,
diff --git a/services/web/frontend/stylesheets/app/editor.less b/services/web/frontend/stylesheets/app/editor.less
index 83e173b80f..0ce416782a 100644
--- a/services/web/frontend/stylesheets/app/editor.less
+++ b/services/web/frontend/stylesheets/app/editor.less
@@ -126,6 +126,34 @@
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 {
height: @editor-toolbar-height;
background-color: @editor-toolbar-bg;
diff --git a/services/web/locales/en.json b/services/web/locales/en.json
index 5388f56f3d..0a34d743a9 100644
--- a/services/web/locales/en.json
+++ b/services/web/locales/en.json
@@ -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.",
"chat_error": "Could not load chat messages, please try again.",
"reconnect": "Try again",
diff --git a/services/web/test/unit/src/Compile/CompileControllerTests.js b/services/web/test/unit/src/Compile/CompileControllerTests.js
index 7117676bba..e9f88db823 100644
--- a/services/web/test/unit/src/Compile/CompileControllerTests.js
+++ b/services/web/test/unit/src/Compile/CompileControllerTests.js
@@ -113,6 +113,7 @@ describe('CompileController', function () {
},
],
pdfDownloadDomain: 'https://compiles.overleaf.test',
+ showFasterCompilesFeedbackUI: false,
})
)
})
@@ -154,6 +155,7 @@ describe('CompileController', function () {
},
],
pdfDownloadDomain: 'https://compiles.overleaf.test/zone/b',
+ showFasterCompilesFeedbackUI: false,
})
)
})
@@ -191,6 +193,7 @@ describe('CompileController', function () {
JSON.stringify({
status: this.status,
outputFiles: this.outputFiles,
+ showFasterCompilesFeedbackUI: false,
})
)
})