Просмотр исходного кода

Merge pull request #22964 from overleaf/ae-project-search-flush

Ensure that open docs are flushed before running full project search

GitOrigin-RevId: 6707cf982018908a37957503add73a085c749f61
Alf Eaton 1 год назад
Родитель
Сommit
f1e1d55d8c

+ 31 - 0
services/web/frontend/js/features/ide-react/editor/open-documents.ts

@@ -95,4 +95,35 @@ export class OpenDocuments {
     }
     return ids
   }
+
+  async awaitBufferedOps(signal: AbortSignal) {
+    if (this.hasUnsavedChanges()) {
+      const { promise, resolve } = Promise.withResolvers<void>()
+
+      let resolved = false
+
+      const listener = () => {
+        if (!this.hasUnsavedChanges()) {
+          debugConsole.log('saved')
+          window.removeEventListener('doc:saved', listener)
+          resolved = true
+          resolve()
+        }
+      }
+
+      window.addEventListener('doc:saved', listener)
+
+      signal.addEventListener('abort', () => {
+        if (!resolved) {
+          debugConsole.log('aborted')
+          window.removeEventListener('doc:saved', listener)
+          resolve()
+        }
+      })
+
+      this.flushAll()
+
+      await promise
+    }
+  }
 }

+ 13 - 35
services/web/frontend/js/features/pdf-preview/util/compiler.js

@@ -30,6 +30,7 @@ export default class DocumentCompiler {
     setError,
     cleanupCompileResult,
     signal,
+    openDocs,
   }) {
     this.compilingRef = compilingRef
     this.projectId = projectId
@@ -41,6 +42,7 @@ export default class DocumentCompiler {
     this.setError = setError
     this.cleanupCompileResult = cleanupCompileResult
     this.signal = signal
+    this.openDocs = openDocs
 
     this.projectRootDocId = null
     this.clsiServerId = null
@@ -61,40 +63,6 @@ export default class DocumentCompiler {
         maxWait: AUTO_COMPILE_MAX_WAIT,
       }
     )
-
-    this._onDocSavedCallback = null
-  }
-
-  async _awaitBufferedOps() {
-    const removeEventListener = () => {
-      clearTimeout(this.pendingOpTimeout)
-      if (this._onDocSavedCallback) {
-        window.removeEventListener('doc:saved', this._onDocSavedCallback)
-        this._onDocSavedCallback = null
-      }
-    }
-
-    removeEventListener()
-    return new Promise(resolve => {
-      if (!this.currentDoc?.hasBufferedOps?.()) {
-        return resolve()
-      }
-
-      this._onDocSavedCallback = () => {
-        // TODO: it's possible that there's more than one doc open with buffered ops, and ideally we'd wait for all docs to be flushed
-        removeEventListener()
-        resolve()
-      }
-
-      clearTimeout(this.pendingOpTimeout)
-      this.pendingOpTimeout = setTimeout(() => {
-        removeEventListener()
-        resolve()
-      }, PENDING_OP_MAX_WAIT)
-
-      window.addEventListener('doc:saved', this._onDocSavedCallback)
-      window.dispatchEvent(new CustomEvent('flush-changes'))
-    })
   }
 
   // The main "compile" function.
@@ -118,7 +86,17 @@ export default class DocumentCompiler {
     }
 
     try {
-      await this._awaitBufferedOps()
+      if (
+        typeof AbortSignal.any === 'function' &&
+        typeof AbortSignal.timeout === 'function'
+      ) {
+        await this.openDocs.awaitBufferedOps(
+          AbortSignal.any([
+            this.signal,
+            AbortSignal.timeout(PENDING_OP_MAX_WAIT),
+          ])
+        )
+      }
 
       // reset values
       this.setChangedAt(0) // TODO: wait for doc:saved?

+ 2 - 1
services/web/frontend/js/shared/context/local-compile-context.tsx

@@ -115,7 +115,7 @@ export const LocalCompileProvider: FC = ({ children }) => {
   const ide = useIdeContext()
 
   const { hasPremiumCompile, isProjectOwner } = useEditorContext()
-  const { openDocId } = useEditorManagerContext()
+  const { openDocId, openDocs } = useEditorManagerContext()
 
   const { _id: projectId, rootDocId } = useProjectContext()
 
@@ -299,6 +299,7 @@ export const LocalCompileProvider: FC = ({ children }) => {
       cleanupCompileResult,
       compilingRef,
       signal,
+      openDocs,
     })
   })
 

+ 3 - 0
services/web/test/frontend/components/pdf-preview/pdf-logs-entries.spec.tsx

@@ -10,6 +10,7 @@ import {
   EditorManagerContext,
 } from '@/features/ide-react/context/editor-manager-context'
 import { EditorView } from '@codemirror/view'
+import { OpenDocuments } from '@/features/ide-react/editor/open-documents'
 
 describe('<PdfLogsEntries/>', function () {
   const fakeFindEntityResult: FindResult = {
@@ -36,6 +37,8 @@ describe('<PdfLogsEntries/>', function () {
   const EditorManagerProvider: FC = ({ children }) => {
     const value = {
       openDocId: cy.spy().as('openDocId'),
+      // @ts-ignore
+      openDocs: new OpenDocuments(),
     } as unknown as EditorManager
 
     return (