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 fd12868987..82ea6e9cb6 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 @@ -10,11 +10,13 @@ import PDFJSWrapper from '../util/pdf-js-wrapper' import withErrorBoundary from '../../../infrastructure/error-boundary' import ErrorBoundaryFallback from './error-boundary-fallback' import { useCompileContext } from '../../../shared/context/compile-context' +import getMeta from '../../../utils/meta' function PdfJsViewer({ url }) { const { _id: projectId } = useProjectContext() - const { setError } = useCompileContext() + const { setError, firstRenderDone } = useCompileContext() + const [timePDFFetched, setTimePDFFetched] = useState() // state values persisted in localStorage to restore on load const [scale, setScale] = usePersistedState( @@ -42,15 +44,32 @@ function PdfJsViewer({ url }) { // listen for initialize event useEffect(() => { if (pdfJsWrapper) { - const handlePagesinit = () => setInitialised(true) + const handlePagesinit = () => { + setInitialised(true) + if (getMeta('ol-trackPdfDownload') && firstRenderDone) { + const visible = !document.hidden + if (!visible) { + firstRenderDone({ + timePDFFetched, + }) + } else { + const timePDFRendered = performance.now() + firstRenderDone({ + timePDFFetched, + timePDFRendered, + }) + } + } + } pdfJsWrapper.eventBus.on('pagesinit', handlePagesinit) return () => pdfJsWrapper.eventBus.off('pagesinit', handlePagesinit) } - }, [pdfJsWrapper]) + }, [pdfJsWrapper, firstRenderDone, timePDFFetched]) // load the PDF document from the URL useEffect(() => { if (pdfJsWrapper && url) { + setTimePDFFetched(performance.now()) setInitialised(false) setError(undefined) 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 1e9f23dd3e..2b2a8693c4 100644 --- a/services/web/frontend/js/features/pdf-preview/util/compiler.js +++ b/services/web/frontend/js/features/pdf-preview/util/compiler.js @@ -3,6 +3,7 @@ import getMeta from '../../../utils/meta' import { sendMBSampled } from '../../../infrastructure/event-tracking' import { deleteJSON, postJSON } from '../../../infrastructure/fetch-json' import { debounce } from 'lodash' +import { trackPdfDownload } from '../../../ide/pdf/controllers/PdfJsMetrics' const AUTO_COMPILE_MAX_WAIT = 5000 // We add a 1 second debounce to sending user changes to server if they aren't @@ -19,6 +20,7 @@ export default class DocumentCompiler { setChangedAt, setCompiling, setData, + setFirstRenderDone, setError, signal, }) { @@ -26,6 +28,7 @@ export default class DocumentCompiler { this.setChangedAt = setChangedAt this.setCompiling = setCompiling this.setData = setData + this.setFirstRenderDone = setFirstRenderDone this.setError = setError this.signal = signal @@ -72,6 +75,8 @@ export default class DocumentCompiler { const params = this.buildCompileParams(options) + const t0 = performance.now() + const data = await postJSON( `/project/${this.project._id}/compile?${params}`, { @@ -86,6 +91,9 @@ export default class DocumentCompiler { signal: this.signal, } ) + const compileTimeClientE2E = performance.now() - t0 + const { firstRenderDone } = trackPdfDownload(data, compileTimeClientE2E) + this.setFirstRenderDone(() => firstRenderDone) data.options = options this.setData(data) } catch (error) { diff --git a/services/web/frontend/js/shared/context/compile-context.js b/services/web/frontend/js/shared/context/compile-context.js index 85a6c5ec48..4dc09e5d3d 100644 --- a/services/web/frontend/js/shared/context/compile-context.js +++ b/services/web/frontend/js/shared/context/compile-context.js @@ -53,6 +53,7 @@ CompileContext.Provider.propTypes = { stopOnValidationError: PropTypes.bool.isRequired, uncompiled: PropTypes.bool, validationIssues: PropTypes.object, + firstRenderDone: PropTypes.func, }), } @@ -91,6 +92,9 @@ export function CompileProvider({ children }) { // data received in response to a compile request const [data, setData] = useState() + // callback to be invoked for PdfJsMetrics + const [firstRenderDone, setFirstRenderDone] = useState() + // whether the project has been compiled yet const [compiledOnce, setCompiledOnce] = useState(false) @@ -150,6 +154,7 @@ export function CompileProvider({ children }) { setChangedAt, setCompiling, setData, + setFirstRenderDone, setError, signal, }) @@ -422,6 +427,7 @@ export function CompileProvider({ children }) { stopOnValidationError, uncompiled, validationIssues, + firstRenderDone, }), [ autoCompile, @@ -452,6 +458,7 @@ export function CompileProvider({ children }) { stopOnValidationError, uncompiled, validationIssues, + firstRenderDone, ] )