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

Improve handling of doc:saved events (#12522)

GitOrigin-RevId: 0ebf198548f6aeecb356405b0c582d3fd64db391
Alf Eaton 3 лет назад
Родитель
Сommit
39df55787c

+ 17 - 2
services/web/frontend/js/features/pdf-preview/hooks/use-compile-triggers.js

@@ -20,7 +20,11 @@ export const startCompileKeypress = event => {
   }
 }
 
-export default function useCompileTriggers(startCompile, setChangedAt) {
+export default function useCompileTriggers(
+  startCompile,
+  setChangedAt,
+  setSavedAt
+) {
   const handleKeyDown = useCallback(
     event => {
       if (startCompileKeypress(event)) {
@@ -54,5 +58,16 @@ export default function useCompileTriggers(startCompile, setChangedAt) {
     setOrTriggerChangedAt(Date.now())
   }, [setOrTriggerChangedAt])
   useEventListener('doc:changed', setChangedAtHandler)
-  useEventListener('doc:saved', setChangedAtHandler) // TODO: store this separately?
+
+  // record when the server acknowledges saving changes
+  const setOrTriggerSavedAt = useDetachAction(
+    'set-saved-at',
+    setSavedAt,
+    'detacher',
+    'detached'
+  )
+  const setSavedAtHandler = useCallback(() => {
+    setOrTriggerSavedAt(Date.now())
+  }, [setOrTriggerSavedAt])
+  useEventListener('doc:saved', setSavedAtHandler)
 }

+ 3 - 0
services/web/frontend/js/features/pdf-preview/util/compiler.js

@@ -20,6 +20,7 @@ export default class DocumentCompiler {
     projectId,
     rootDocId,
     setChangedAt,
+    setSavedAt,
     setCompiling,
     setData,
     setFirstRenderDone,
@@ -32,6 +33,7 @@ export default class DocumentCompiler {
     this.projectId = projectId
     this.rootDocId = rootDocId
     this.setChangedAt = setChangedAt
+    this.setSavedAt = setSavedAt
     this.setCompiling = setCompiling
     this.setData = setData
     this.setFirstRenderDone = setFirstRenderDone
@@ -83,6 +85,7 @@ export default class DocumentCompiler {
     try {
       // reset values
       this.setChangedAt(0) // TODO: wait for doc:saved?
+      this.setSavedAt(0)
       this.validationIssues = undefined
 
       window.dispatchEvent(new CustomEvent('flush-changes')) // TODO: wait for this?

+ 3 - 2
services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts

@@ -56,7 +56,8 @@ function useCodeMirrorScope(view: EditorView) {
 
   // set up scope listeners
 
-  const { logEntryAnnotations, uncompiled, compiling } = useCompileContext()
+  const { logEntryAnnotations, editedSinceCompileStarted, compiling } =
+    useCompileContext()
 
   const [loadingThreads] = useScopeValue<boolean>('loadingThreads')
 
@@ -394,7 +395,7 @@ function useCodeMirrorScope(view: EditorView) {
   // the project "changed at" date is reset at the start of the compile, i.e. "the project hasn't changed",
   // but we don't want to display the compile log diagnostics from the previous compile.
   const enableCompileLogLinter =
-    !syntaxValidation || (!uncompiled && !compiling)
+    !syntaxValidation || (!editedSinceCompileStarted && !compiling)
 
   // store enableCompileLogLinter in a ref for use in useEffect
   const enableCompileLogLinterRef = useRef(enableCompileLogLinter)

+ 17 - 1
services/web/frontend/js/shared/context/detach-compile-context.js

@@ -30,6 +30,7 @@ export function DetachCompileProvider({ children }) {
     compiling: _compiling,
     deliveryLatencies: _deliveryLatencies,
     draft: _draft,
+    editedSinceCompileStarted: _editedSinceCompileStarted,
     error: _error,
     fileList: _fileList,
     forceNewDomainVariant: _forceNewDomainVariant,
@@ -69,6 +70,7 @@ export function DetachCompileProvider({ children }) {
     startCompile: _startCompile,
     stopCompile: _stopCompile,
     setChangedAt: _setChangedAt,
+    setSavedAt: _setSavedAt,
     clearCache: _clearCache,
   } = localCompileContext
 
@@ -224,6 +226,12 @@ export function DetachCompileProvider({ children }) {
     'detacher',
     'detached'
   )
+  const [editedSinceCompileStarted] = useDetachStateWatcher(
+    'editedSinceCompileStarted',
+    _editedSinceCompileStarted,
+    'detacher',
+    'detached'
+  )
   const [validationIssues] = useDetachStateWatcher(
     'validationIssues',
     _validationIssues,
@@ -345,6 +353,12 @@ export function DetachCompileProvider({ children }) {
     'detached',
     'detacher'
   )
+  const setSavedAt = useDetachAction(
+    'setSavedAt',
+    _setSavedAt,
+    'detached',
+    'detacher'
+  )
   const clearCache = useDetachAction(
     'clearCache',
     _clearCache,
@@ -352,7 +366,7 @@ export function DetachCompileProvider({ children }) {
     'detacher'
   )
 
-  useCompileTriggers(startCompile, setChangedAt)
+  useCompileTriggers(startCompile, setChangedAt, setSavedAt)
   useEffect(() => {
     // Sync the split test variant across the editor and pdf-detach.
     const variants = getMeta('ol-splitTestVariants') || {}
@@ -370,6 +384,7 @@ export function DetachCompileProvider({ children }) {
       compiling,
       deliveryLatencies,
       draft,
+      editedSinceCompileStarted,
       error,
       fileList,
       forceNewDomainVariant,
@@ -423,6 +438,7 @@ export function DetachCompileProvider({ children }) {
       deliveryLatencies,
       draft,
       error,
+      editedSinceCompileStarted,
       fileList,
       forceNewDomainVariant,
       hasChanges,

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

@@ -123,9 +123,13 @@ export function LocalCompileProvider({ children }) {
     setPdfUrl(pdfFile?.pdfUrl)
   }, [pdfFile, setPdfDownloadUrl, setPdfUrl])
 
-  // the project is considered to be "uncompiled" if a doc has changed since the last compile started
+  // the project is considered to be "uncompiled" if a doc has changed, or finished saving, since the last compile started.
   const [uncompiled, setUncompiled] = useScopeValue('pdf.uncompiled')
 
+  // whether a doc has been edited since the last compile started
+  const [editedSinceCompileStarted, setEditedSinceCompileStarted] =
+    useState(false)
+
   // the id of the CLSI server which ran the compile
   const [clsiServerId, setClsiServerId] = useState()
 
@@ -223,9 +227,12 @@ export function LocalCompileProvider({ children }) {
   // whether syntax validation is enabled globally
   const [syntaxValidation] = useScopeValue('settings.syntaxValidation')
 
-  // the timestamp that a doc was last changed or saved
+  // the timestamp that a doc was last changed
   const [changedAt, setChangedAt] = useState(0)
 
+  // the timestamp that a doc was last saved
+  const [savedAt, setSavedAt] = useState(0)
+
   const { signal } = useAbortController()
 
   const cleanupCompileResult = useCallback(() => {
@@ -246,6 +253,7 @@ export function LocalCompileProvider({ children }) {
       projectId,
       rootDocId,
       setChangedAt,
+      setSavedAt,
       setCompiling,
       setData,
       setFirstRenderDone,
@@ -272,10 +280,13 @@ export function LocalCompileProvider({ children }) {
     compiler.setOption('stopOnFirstError', stopOnFirstError)
   }, [compiler, stopOnFirstError])
 
-  // pass the "uncompiled" value up into the scope for use outside this context provider
   useEffect(() => {
-    setUncompiled(changedAt > 0)
-  }, [setUncompiled, changedAt])
+    setUncompiled(changedAt > 0 || savedAt > 0)
+  }, [setUncompiled, changedAt, savedAt])
+
+  useEffect(() => {
+    setEditedSinceCompileStarted(changedAt > 0)
+  }, [setEditedSinceCompileStarted, changedAt])
 
   // always compile the PDF once after opening the project, after the doc has loaded
   useEffect(() => {
@@ -468,13 +479,13 @@ export function LocalCompileProvider({ children }) {
   // call the debounced autocompile function if the project is available for auto-compiling and it has changed
   useEffect(() => {
     if (canAutoCompile) {
-      if (changedAt > 0) {
+      if (changedAt > 0 || savedAt > 0) {
         compiler.debouncedAutoCompile()
       }
     } else {
       compiler.debouncedAutoCompile.cancel()
     }
-  }, [compiler, canAutoCompile, changedAt])
+  }, [compiler, canAutoCompile, changedAt, savedAt])
 
   // cancel debounced recompile on unmount
   useEffect(() => {
@@ -533,6 +544,7 @@ export function LocalCompileProvider({ children }) {
       compiling,
       deliveryLatencies,
       draft,
+      editedSinceCompileStarted,
       error,
       fileList,
       forceNewDomainVariant,
@@ -573,6 +585,7 @@ export function LocalCompileProvider({ children }) {
       validationIssues,
       firstRenderDone,
       setChangedAt,
+      setSavedAt,
       cleanupCompileResult,
     }),
     [
@@ -585,6 +598,7 @@ export function LocalCompileProvider({ children }) {
       compiling,
       deliveryLatencies,
       draft,
+      editedSinceCompileStarted,
       error,
       fileList,
       forceNewDomainVariant,
@@ -620,6 +634,7 @@ export function LocalCompileProvider({ children }) {
       validationIssues,
       firstRenderDone,
       setChangedAt,
+      setSavedAt,
       cleanupCompileResult,
       setShowLogs,
       toggleLogs,