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

Ensure that open docs are flushed before running full project search

GitOrigin-RevId: 6707cf982018908a37957503add73a085c749f61
This commit is contained in:
Alf Eaton
2025-01-23 09:34:58 +00:00
committed by Copybot
parent fdc4ccc62b
commit dfd448cd85
4 changed files with 49 additions and 36 deletions

View File

@@ -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
}
}
}

View File

@@ -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?

View File

@@ -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,
})
})

View File

@@ -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 (