From 7a315bfa4d51cd30aadcacf08eb9522f9e4bfc08 Mon Sep 17 00:00:00 2001 From: Hugh O'Brien Date: Fri, 1 May 2020 14:59:55 +0100 Subject: [PATCH] Merge pull request #2759 from overleaf/hb-read-only-on-connection-lost Read only mode on lost connection and local file contents on Out of Sync error GitOrigin-RevId: e31a259be122ad162e98746cd06a7794a95e78fa --- services/web/app/views/project/editor.pug | 25 +++++++++++++ .../frontend/js/ide/editor/EditorManager.js | 5 +-- .../SavingNotificationController.js | 16 ++++++++- .../js/ide/permissions/PermissionsManager.js | 2 ++ services/web/frontend/js/ide/services/ide.js | 36 +++++++++++++++++-- .../web/frontend/stylesheets/app/editor.less | 26 +++++++++++++- 6 files changed, 104 insertions(+), 6 deletions(-) diff --git a/services/web/app/views/project/editor.pug b/services/web/app/views/project/editor.pug index 6f10ac05de..5177c0afe2 100644 --- a/services/web/app/views/project/editor.pug +++ b/services/web/app/views/project/editor.pug @@ -120,6 +120,31 @@ block content .modal-footer button.btn.btn-info(ng-click="done()") #{translate("ok")} + script(type="text/ng-template", id="outOfSyncModalTemplate") + .modal-header + button.close( + type="button" + data-dismiss="modal" + ng-click="done()" + aria-label="Close" + ) + span(aria-hidden="true") × + h3 {{ title }} + .modal-body(ng-bind-html="message") + + .modal-body + button.btn.btn-info( + ng-init="showFileContents = false" + ng-click="showFileContents = !showFileContents" + ) + | {{showFileContents ? "Hide" : "Show"}} Local File Contents + .text-preview(ng-show="showFileContents") + .scroll-container + | {{editorContent}} + + .modal-footer + button.btn.btn-info(ng-click="done()") #{translate("ok")} + script(type="text/ng-template", id="lockEditorModalTemplate") .modal-header h3 {{ title }} diff --git a/services/web/frontend/js/ide/editor/EditorManager.js b/services/web/frontend/js/ide/editor/EditorManager.js index eccc19b957..ab8eb8913c 100644 --- a/services/web/frontend/js/ide/editor/EditorManager.js +++ b/services/web/frontend/js/ide/editor/EditorManager.js @@ -237,9 +237,10 @@ define([ } else { this.ide.socket.disconnect() this.ide.reportError(error, meta) - this.ide.showGenericMessageModal( + this.ide.showOutOfSyncModal( 'Out of sync', - "Sorry, this file has gone out of sync and we need to do a full refresh.
Please see this help guide for more information" + "Sorry, this file has gone out of sync and we need to do a full refresh.
Please see this help guide for more information", + sharejs_doc.doc._doc.snapshot ) } const removeHandler = this.$scope.$on('project:joined', () => { diff --git a/services/web/frontend/js/ide/editor/controllers/SavingNotificationController.js b/services/web/frontend/js/ide/editor/controllers/SavingNotificationController.js index fcb0d339dd..b08a67c33f 100644 --- a/services/web/frontend/js/ide/editor/controllers/SavingNotificationController.js +++ b/services/web/frontend/js/ide/editor/controllers/SavingNotificationController.js @@ -26,6 +26,7 @@ define(['../../../base', '../Document'], (App, Document) => }) let lockEditorModal = null // modal showing "connection lost" + let originalPermissionsLevel const MAX_UNSAVED_SECONDS = 15 // lock the editor after this time if unsaved $scope.docSavingStatus = {} @@ -62,11 +63,24 @@ define(['../../../base', '../Document'], (App, Document) => 'Connection lost', 'Sorry, the connection to the server is down.' ) - lockEditorModal.result.finally(() => (lockEditorModal = null)) // unset the modal if connection comes back + + // put editor in readOnly mode + originalPermissionsLevel = ide.$scope.permissionsLevel + ide.$scope.permissionsLevel = 'readOnly' + + lockEditorModal.result.finally(() => { + lockEditorModal = null // unset the modal if connection comes back + // restore original permissions + ide.$scope.permissionsLevel = originalPermissionsLevel + }) } if (lockEditorModal && newUnsavedCount === 0) { lockEditorModal.dismiss('connection back up') + // restore original permissions if they were changed + if (originalPermissionsLevel) { + ide.$scope.permissionsLevel = originalPermissionsLevel + } } // for performance, only update the display if the old or new diff --git a/services/web/frontend/js/ide/permissions/PermissionsManager.js b/services/web/frontend/js/ide/permissions/PermissionsManager.js index 9d0e9c97cd..4853c7003d 100644 --- a/services/web/frontend/js/ide/permissions/PermissionsManager.js +++ b/services/web/frontend/js/ide/permissions/PermissionsManager.js @@ -27,6 +27,8 @@ define([], function() { if (permissionsLevel != null) { if (permissionsLevel === 'readOnly') { this.$scope.permissions.read = true + this.$scope.permissions.write = false + this.$scope.permissions.admin = false this.$scope.permissions.comment = true } else if (permissionsLevel === 'readAndWrite') { this.$scope.permissions.read = true diff --git a/services/web/frontend/js/ide/services/ide.js b/services/web/frontend/js/ide/services/ide.js index d2da385a74..c7964975e4 100644 --- a/services/web/frontend/js/ide/services/ide.js +++ b/services/web/frontend/js/ide/services/ide.js @@ -91,12 +91,30 @@ define(['../../base'], function(App) { } }) + ide.showOutOfSyncModal = (title, message, editorContent) => + $modal.open({ + templateUrl: 'outOfSyncModalTemplate', + controller: 'OutOfSyncModalController', + resolve: { + title() { + return title + }, + message() { + return message + }, + editorContent() { + return editorContent + } + }, + windowClass: 'out-of-sync-modal' + }) + ide.showLockEditorMessageModal = (title, message) => // modal to block the editor when connection is down $modal.open({ templateUrl: 'lockEditorModalTemplate', controller: 'GenericMessageModalController', - backdrop: 'static', // prevent dismiss by click on background + backdrop: false, // not dismissable by clicking background keyboard: false, // prevent dismiss via keyboard resolve: { title() { @@ -112,7 +130,7 @@ define(['../../base'], function(App) { return ide }) - return App.controller('GenericMessageModalController', function( + App.controller('GenericMessageModalController', function( $scope, $modalInstance, title, @@ -123,6 +141,20 @@ define(['../../base'], function(App) { return ($scope.done = () => $modalInstance.close()) }) + + App.controller('OutOfSyncModalController', function( + $scope, + $modalInstance, + title, + message, + editorContent + ) { + $scope.title = title + $scope.message = message + $scope.editorContent = editorContent + + return ($scope.done = () => $modalInstance.close()) + }) }) function __guard__(value, transform) { diff --git a/services/web/frontend/stylesheets/app/editor.less b/services/web/frontend/stylesheets/app/editor.less index cf0320f4c6..ee0a93cf1c 100644 --- a/services/web/frontend/stylesheets/app/editor.less +++ b/services/web/frontend/stylesheets/app/editor.less @@ -518,8 +518,32 @@ CodeMirror .modal.lock-editor-modal { display: flex !important; + background-color: rgba(0, 0, 0, 0.3); + overflow-y: hidden; + pointer-events: none; .modal-dialog { - margin: auto; + top: @line-height-computed; + } +} + +.out-of-sync-modal { + .text-preview { + margin-top: @line-height-computed / 2; + .scroll-container { + max-height: 360px; + background-color: white; + font-size: 0.8em; + line-height: 1.1em; + overflow: auto; + border: 1px solid @gray-lighter; + padding-left: 12px; + padding-right: 12px; + padding-top: 8px; + padding-bottom: 8px; + text-align: left; + white-space: pre; + font-family: monospace; + } } }