Преглед изворни кода

Merge pull request #5395 from overleaf/msm-pdf-metrics

Added PdfJsMetrics to React PDF Viewer

GitOrigin-RevId: ff749d67baec243ca2c8e51409754716f4cef62c
June Kelly пре 5 година
родитељ
комит
4f29ca5cbd

+ 22 - 3
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 withErrorBoundary from '../../../infrastructure/error-boundary'
 import ErrorBoundaryFallback from './error-boundary-fallback'
 import ErrorBoundaryFallback from './error-boundary-fallback'
 import { useCompileContext } from '../../../shared/context/compile-context'
 import { useCompileContext } from '../../../shared/context/compile-context'
+import getMeta from '../../../utils/meta'
 
 
 function PdfJsViewer({ url }) {
 function PdfJsViewer({ url }) {
   const { _id: projectId } = useProjectContext()
   const { _id: projectId } = useProjectContext()
 
 
-  const { setError } = useCompileContext()
+  const { setError, firstRenderDone } = useCompileContext()
+  const [timePDFFetched, setTimePDFFetched] = useState()
 
 
   // state values persisted in localStorage to restore on load
   // state values persisted in localStorage to restore on load
   const [scale, setScale] = usePersistedState(
   const [scale, setScale] = usePersistedState(
@@ -42,15 +44,32 @@ function PdfJsViewer({ url }) {
   // listen for initialize event
   // listen for initialize event
   useEffect(() => {
   useEffect(() => {
     if (pdfJsWrapper) {
     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)
       pdfJsWrapper.eventBus.on('pagesinit', handlePagesinit)
       return () => pdfJsWrapper.eventBus.off('pagesinit', handlePagesinit)
       return () => pdfJsWrapper.eventBus.off('pagesinit', handlePagesinit)
     }
     }
-  }, [pdfJsWrapper])
+  }, [pdfJsWrapper, firstRenderDone, timePDFFetched])
 
 
   // load the PDF document from the URL
   // load the PDF document from the URL
   useEffect(() => {
   useEffect(() => {
     if (pdfJsWrapper && url) {
     if (pdfJsWrapper && url) {
+      setTimePDFFetched(performance.now())
       setInitialised(false)
       setInitialised(false)
       setError(undefined)
       setError(undefined)
 
 

+ 8 - 0
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 { sendMBSampled } from '../../../infrastructure/event-tracking'
 import { deleteJSON, postJSON } from '../../../infrastructure/fetch-json'
 import { deleteJSON, postJSON } from '../../../infrastructure/fetch-json'
 import { debounce } from 'lodash'
 import { debounce } from 'lodash'
+import { trackPdfDownload } from '../../../ide/pdf/controllers/PdfJsMetrics'
 
 
 const AUTO_COMPILE_MAX_WAIT = 5000
 const AUTO_COMPILE_MAX_WAIT = 5000
 // We add a 1 second debounce to sending user changes to server if they aren't
 // 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,
     setChangedAt,
     setCompiling,
     setCompiling,
     setData,
     setData,
+    setFirstRenderDone,
     setError,
     setError,
     signal,
     signal,
   }) {
   }) {
@@ -26,6 +28,7 @@ export default class DocumentCompiler {
     this.setChangedAt = setChangedAt
     this.setChangedAt = setChangedAt
     this.setCompiling = setCompiling
     this.setCompiling = setCompiling
     this.setData = setData
     this.setData = setData
+    this.setFirstRenderDone = setFirstRenderDone
     this.setError = setError
     this.setError = setError
     this.signal = signal
     this.signal = signal
 
 
@@ -72,6 +75,8 @@ export default class DocumentCompiler {
 
 
       const params = this.buildCompileParams(options)
       const params = this.buildCompileParams(options)
 
 
+      const t0 = performance.now()
+
       const data = await postJSON(
       const data = await postJSON(
         `/project/${this.project._id}/compile?${params}`,
         `/project/${this.project._id}/compile?${params}`,
         {
         {
@@ -86,6 +91,9 @@ export default class DocumentCompiler {
           signal: this.signal,
           signal: this.signal,
         }
         }
       )
       )
+      const compileTimeClientE2E = performance.now() - t0
+      const { firstRenderDone } = trackPdfDownload(data, compileTimeClientE2E)
+      this.setFirstRenderDone(() => firstRenderDone)
       data.options = options
       data.options = options
       this.setData(data)
       this.setData(data)
     } catch (error) {
     } catch (error) {

+ 7 - 0
services/web/frontend/js/shared/context/compile-context.js

@@ -53,6 +53,7 @@ CompileContext.Provider.propTypes = {
     stopOnValidationError: PropTypes.bool.isRequired,
     stopOnValidationError: PropTypes.bool.isRequired,
     uncompiled: PropTypes.bool,
     uncompiled: PropTypes.bool,
     validationIssues: PropTypes.object,
     validationIssues: PropTypes.object,
+    firstRenderDone: PropTypes.func,
   }),
   }),
 }
 }
 
 
@@ -91,6 +92,9 @@ export function CompileProvider({ children }) {
   // data received in response to a compile request
   // data received in response to a compile request
   const [data, setData] = useState()
   const [data, setData] = useState()
 
 
+  // callback to be invoked for PdfJsMetrics
+  const [firstRenderDone, setFirstRenderDone] = 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)
 
 
@@ -150,6 +154,7 @@ export function CompileProvider({ children }) {
       setChangedAt,
       setChangedAt,
       setCompiling,
       setCompiling,
       setData,
       setData,
+      setFirstRenderDone,
       setError,
       setError,
       signal,
       signal,
     })
     })
@@ -422,6 +427,7 @@ export function CompileProvider({ children }) {
       stopOnValidationError,
       stopOnValidationError,
       uncompiled,
       uncompiled,
       validationIssues,
       validationIssues,
+      firstRenderDone,
     }),
     }),
     [
     [
       autoCompile,
       autoCompile,
@@ -452,6 +458,7 @@ export function CompileProvider({ children }) {
       stopOnValidationError,
       stopOnValidationError,
       uncompiled,
       uncompiled,
       validationIssues,
       validationIssues,
+      firstRenderDone,
     ]
     ]
   )
   )