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

Disable track changes for reviewers in free projects (#24368)

* Disable track changes for reviewers in free projects

* cleanup_unused_locales

GitOrigin-RevId: 806ee20c0aed5ef61352041782af620cec72ed70
Domagoj Kriskovic 1 год назад
Родитель
Сommit
7f67df2468

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

@@ -183,7 +183,6 @@
   "blog": "",
   "browser": "",
   "by_subscribing_you_agree_to_our_terms_of_service": "",
-  "can_add_tracked_changes_and_comments": "",
   "can_edit": "",
   "can_edit_content": "",
   "can_link_institution_email_acct_to_institution_acct": "",
@@ -268,6 +267,7 @@
   "column_width_is_custom_click_to_resize": "",
   "column_width_is_x_click_to_resize": "",
   "comment": "",
+  "comment_only": "",
   "commit": "",
   "common": "",
   "common_causes_of_compile_timeouts_include": "",
@@ -472,6 +472,7 @@
   "editor_only": "",
   "editor_only_hide_pdf": "",
   "editor_theme": "",
+  "edits_become_suggestions": "",
   "educational_disclaimer": "",
   "educational_disclaimer_heading": "",
   "educational_percent_discount_applied": "",

+ 21 - 4
services/web/frontend/js/features/ide-react/context/permissions-context.tsx

@@ -9,6 +9,7 @@ import {
 import useScopeValue from '@/shared/hooks/use-scope-value'
 import { DeepReadonly } from '../../../../../types/utils'
 import useViewerPermissions from '@/shared/hooks/use-viewer-permissions'
+import { useProjectContext } from '@/shared/context/project-context'
 
 export const PermissionsContext = createContext<Permissions | undefined>(
   undefined
@@ -71,6 +72,13 @@ const linkSharingWarningPermissionsMap: typeof permissionsMap = {
   owner: permissionsMap.owner,
 }
 
+const noTrackChangesPermissionsMap: typeof permissionsMap = {
+  readOnly: permissionsMap.readOnly,
+  readAndWrite: permissionsMap.readAndWrite,
+  review: { ...permissionsMap.review, trackedWrite: false },
+  owner: permissionsMap.owner,
+}
+
 export const PermissionsProvider: React.FC = ({ children }) => {
   const [permissions, setPermissions] =
     useScopeValue<Readonly<Permissions>>('permissions')
@@ -80,18 +88,27 @@ export const PermissionsProvider: React.FC = ({ children }) => {
   }
   const hasViewerPermissions = useViewerPermissions()
   const anonymous = getMeta('ol-anonymous')
+  const project = useProjectContext()
 
   useEffect(() => {
     let activePermissionsMap
     if (hasViewerPermissions) {
       activePermissionsMap = linkSharingWarningPermissionsMap
+    } else if (anonymous) {
+      activePermissionsMap = anonymousPermissionsMap
+    } else if (!project.features.trackChanges) {
+      activePermissionsMap = noTrackChangesPermissionsMap
     } else {
-      activePermissionsMap = anonymous
-        ? anonymousPermissionsMap
-        : permissionsMap
+      activePermissionsMap = permissionsMap
     }
     setPermissions(activePermissionsMap[permissionsLevel])
-  }, [anonymous, permissionsLevel, setPermissions, hasViewerPermissions])
+  }, [
+    anonymous,
+    permissionsLevel,
+    setPermissions,
+    hasViewerPermissions,
+    project.features.trackChanges,
+  ])
 
   useEffect(() => {
     if (connectionState.forceDisconnected) {

+ 40 - 25
services/web/frontend/js/features/review-panel-new/components/review-mode-switcher.tsx

@@ -1,4 +1,4 @@
-import { forwardRef, memo, MouseEventHandler } from 'react'
+import { forwardRef, memo, MouseEventHandler, useState } from 'react'
 import {
   Dropdown,
   DropdownMenu,
@@ -17,6 +17,8 @@ import { usePermissionsContext } from '@/features/ide-react/context/permissions-
 import usePersistedState from '@/shared/hooks/use-persisted-state'
 import { sendMB } from '@/infrastructure/event-tracking'
 import { useEditorContext } from '@/shared/context/editor-context'
+import { useProjectContext } from '@/shared/context/project-context'
+import UpgradeTrackChangesModal from '@/features/source-editor/components/review-panel/upgrade-track-changes-modal'
 
 type Mode = 'view' | 'review' | 'edit'
 
@@ -26,15 +28,17 @@ const useCurrentMode = (): Mode => {
   const trackChangesForCurrentUser =
     trackChanges?.onForEveryone ||
     (user && user.id && trackChanges?.onForMembers[user.id])
-  const { write, trackedWrite } = usePermissionsContext()
+  const { permissionsLevel } = useEditorContext()
 
-  if (write && !trackChangesForCurrentUser) {
-    return 'edit'
-  } else if (trackedWrite) {
+  if (permissionsLevel === 'readOnly') {
+    return 'view'
+  } else if (permissionsLevel === 'review') {
     return 'review'
+  } else if (trackChangesForCurrentUser) {
+    return 'review'
+  } else {
+    return 'edit'
   }
-
-  return 'view'
 }
 
 function ReviewModeSwitcher() {
@@ -43,9 +47,10 @@ function ReviewModeSwitcher() {
     useTrackChangesStateActionsContext()
   const mode = useCurrentMode()
   const { permissionsLevel } = useEditorContext()
-
   const { write, trackedWrite } = usePermissionsContext()
-  const showViewOption = !trackedWrite
+  const project = useProjectContext()
+  const [showUpgradeModal, setShowUpgradeModal] = useState(false)
+  const showViewOption = permissionsLevel === 'readOnly'
 
   return (
     <div className="review-mode-switcher-container">
@@ -58,6 +63,9 @@ function ReviewModeSwitcher() {
           <OLDropdownMenuItem
             disabled={!write}
             onClick={() => {
+              if (mode === 'edit') {
+                return
+              }
               sendMB('editing-mode-change', {
                 role: permissionsLevel,
                 previousMode: mode,
@@ -72,16 +80,27 @@ function ReviewModeSwitcher() {
             {t('editing')}
           </OLDropdownMenuItem>
           <OLDropdownMenuItem
-            disabled={!trackedWrite}
+            disabled={permissionsLevel === 'readOnly'}
             onClick={() => {
-              sendMB('editing-mode-change', {
-                role: permissionsLevel,
-                previousMode: mode,
-                newMode: 'review',
-              })
-              saveTrackChangesForCurrentUser(true)
+              if (mode === 'review') {
+                return
+              }
+              if (!project.features.trackChanges) {
+                setShowUpgradeModal(true)
+              } else {
+                sendMB('editing-mode-change', {
+                  role: permissionsLevel,
+                  previousMode: mode,
+                  newMode: 'review',
+                })
+                saveTrackChangesForCurrentUser(true)
+              }
             }}
-            description={t('can_add_tracked_changes_and_comments')}
+            description={
+              permissionsLevel === 'review' && !trackedWrite
+                ? t('comment_only')
+                : t('edits_become_suggestions')
+            }
             leadingIcon="rate_review"
             active={trackedWrite && mode === 'review'}
           >
@@ -89,14 +108,6 @@ function ReviewModeSwitcher() {
           </OLDropdownMenuItem>
           {showViewOption && (
             <OLDropdownMenuItem
-              onClick={() => {
-                sendMB('editing-mode-change', {
-                  role: permissionsLevel,
-                  previousMode: mode,
-                  newMode: 'view',
-                })
-                saveTrackChangesForCurrentUser(true)
-              }}
               description={t('can_view_content')}
               leadingIcon="visibility"
               active={mode === 'view'}
@@ -106,6 +117,10 @@ function ReviewModeSwitcher() {
           )}
         </DropdownMenu>
       </Dropdown>
+      <UpgradeTrackChangesModal
+        show={showUpgradeModal}
+        setShow={setShowUpgradeModal}
+      />
     </div>
   )
 }

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

@@ -244,7 +244,6 @@
   "by_joining_labs": "By joining Labs, you agree to receive occasional emails and updates from Overleaf—for example, to request your feedback. You also agree to our <0>terms of service</0> and <1>privacy notice</1>.",
   "by_registering_you_agree_to_our_terms_of_service": "By registering, you agree to our <0>terms of service</0> and <1>privacy notice</1>.",
   "by_subscribing_you_agree_to_our_terms_of_service": "By subscribing, you agree to our <0>terms of service</0>.",
-  "can_add_tracked_changes_and_comments": "Can add tracked changes and comments",
   "can_edit": "Can edit",
   "can_edit_content": "Can edit content",
   "can_link_institution_email_acct_to_institution_acct": "You can now link your <b>__email__</b> <b>__appName__</b> account to your <b>__institutionName__</b> institutional account.",
@@ -349,6 +348,7 @@
   "column_width_is_custom_click_to_resize": "Column width is custom. Click to resize",
   "column_width_is_x_click_to_resize": "Column width is __width__. Click to resize",
   "comment": "Comment",
+  "comment_only": "Comment only",
   "commit": "Commit",
   "common": "Common",
   "common_causes_of_compile_timeouts_include": "Common causes of compile timeouts include",
@@ -611,6 +611,7 @@
   "editor_only": "Editor only",
   "editor_only_hide_pdf": "Editor only <0>(hide PDF)</0>",
   "editor_theme": "Editor theme",
+  "edits_become_suggestions": "Edits become suggestions",
   "educational_disclaimer": "I confirm that users will be students or faculty using Overleaf primarily for study and teaching, and can provide evidence of this if requested.",
   "educational_disclaimer_heading": "Educational discount confirmation",
   "educational_percent_discount_applied": "__percent__% educational discount applied!",