فهرست منبع

Merge pull request #20052 from overleaf/em-tracked-deletes-limit

Include tracked deletes when limiting document size

GitOrigin-RevId: 9d7b2870001fb942eaa92db78993fee1ddb3937c
Eric Mc Sween 1 سال پیش
والد
کامیت
8b4b454b97

+ 10 - 0
libraries/ranges-tracker/index.cjs

@@ -768,6 +768,16 @@ class RangesTracker {
     return this._dirtyState
   }
 
+  getTrackedDeletesLength() {
+    let length = 0
+    for (const change of this.changes) {
+      if (change.op.d != null) {
+        length += change.op.d.length
+      }
+    }
+    return length
+  }
+
   _markAsDirty(object, type, action) {
     this._dirtyState[type][action][object.id] = object
   }

+ 1 - 0
services/web/frontend/extracted-translations.json

@@ -326,6 +326,7 @@
   "do_you_want_to_overwrite_them": "",
   "document_too_long": "",
   "document_too_long_detail": "",
+  "document_too_long_tracked_deletes": "",
   "document_updated_externally": "",
   "document_updated_externally_detail": "",
   "documentation": "",

+ 8 - 4
services/web/frontend/js/features/ide-react/context/editor-manager-context.tsx

@@ -548,10 +548,14 @@ export const EditorManagerProvider: FC = ({ children }) => {
 
       if (message.includes('maxDocLength')) {
         openDoc(doc, { forceReopen: true })
-        showGenericMessageModal(
-          t('document_too_long'),
-          t('document_too_long_detail')
-        )
+        const hasTrackedDeletes =
+          document.ranges != null &&
+          document.ranges.changes.some(change => 'd' in change.op)
+        const explanation = hasTrackedDeletes
+          ? `${t('document_too_long_detail')} ${t('document_too_long_tracked_deletes')}`
+          : t('document_too_long_detail')
+
+        showGenericMessageModal(t('document_too_long'), explanation)
         setDocTooLongErrorShown(true)
       } else if (/too many comments or tracked changes/.test(message)) {
         showGenericMessageModal(

+ 1 - 3
services/web/frontend/js/features/ide-react/editor/document-container.ts

@@ -127,9 +127,7 @@ export class DocumentContainer extends EventEmitter {
     if (this.doc) {
       this.doc.attachToCM6(this.cm6)
     }
-    if (this.cm6) {
-      this.cm6.on('change', this.checkConsistency)
-    }
+    this.cm6.on('change', this.checkConsistency)
   }
 
   detachFromCM6() {

+ 17 - 6
services/web/frontend/js/features/source-editor/extensions/realtime.ts

@@ -1,6 +1,7 @@
 import { Prec, Transaction, Annotation, ChangeSpec } from '@codemirror/state'
 import { EditorView, ViewPlugin } from '@codemirror/view'
 import { EventEmitter } from 'events'
+import RangesTracker from '@overleaf/ranges-tracker'
 import { ShareDoc } from '../../../../../types/share-doc'
 import { debugConsole } from '@/utils/debugging'
 import { DocumentContainer } from '@/features/ide-react/editor/document-container'
@@ -45,7 +46,7 @@ export const realtime = (
     return {
       update(update) {
         if (update.docChanged) {
-          editor.handleUpdateFromCM(update.transactions)
+          editor.handleUpdateFromCM(update.transactions, currentDoc.ranges)
         }
       },
       destroy() {
@@ -166,8 +167,13 @@ export class EditorFacade extends EventEmitter {
 
   // Process an update from CodeMirror, applying changes to the
   // ShareJs doc if appropriate
-  handleUpdateFromCM(transactions: readonly Transaction[]) {
+  handleUpdateFromCM(
+    transactions: readonly Transaction[],
+    ranges?: RangesTracker
+  ) {
     const shareDoc = this.shareDoc
+    const trackedDeletesLength =
+      ranges != null ? ranges.getTrackedDeletesLength() : 0
 
     if (!shareDoc) {
       throw new Error('Trying to process updates with no shareDoc')
@@ -181,10 +187,15 @@ export class EditorFacade extends EventEmitter {
           return
         }
 
-        if (
-          this.maxDocLength &&
-          transaction.changes.desc.newLength >= this.maxDocLength
-        ) {
+        // This is an approximation. Some deletes could have generated new
+        // tracked deletes since we measured trackedDeletesLength at the top of
+        // the function. Unfortunately, the ranges tracker is only updated
+        // after all transactions are processed, so it's not easy to get an
+        // exact number.
+        const fullDocLength =
+          transaction.changes.desc.newLength + trackedDeletesLength
+
+        if (this.maxDocLength && fullDocLength >= this.maxDocLength) {
           shareDoc.emit(
             'error',
             new Error('document length is greater than maxDocLength')

+ 2 - 1
services/web/locales/en.json

@@ -461,7 +461,8 @@
   "do_you_want_to_overwrite_it_plural": "Do you want to overwrite them?",
   "do_you_want_to_overwrite_them": "Do you want to overwrite them?",
   "document_too_long": "Document Too Long",
-  "document_too_long_detail": "Sorry, this file is too long to be edited manually. Please upload it directly.",
+  "document_too_long_detail": "Sorry, this file is too long to be edited manually. Please try to split it into smaller files.",
+  "document_too_long_tracked_deletes": "You can also accept pending deletions to reduce the size of the file.",
   "document_updated_externally": "Document Updated Externally",
   "document_updated_externally_detail": "This document was just updated externally. Any recent changes you have made may have been overwritten. To see previous versions, please look in the history.",
   "documentation": "Documentation",

+ 1 - 0
services/web/test/frontend/features/source-editor/helpers/mock-doc.ts

@@ -78,6 +78,7 @@ export const mockDoc = (content = defaultContent) => {
       comments: [],
       getIdSeed: () => '123',
       setIdSeed: () => {},
+      getTrackedDeletesLength: () => 0,
     },
     setTrackChangesIdSeeds: () => {},
     getTrackingChanges: () => true,