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

Merge pull request #24225 from overleaf/em-reviewers-share-modal

Count reviewers towards collaborator limit in share modal

GitOrigin-RevId: 27ec3a787124be7590791412d914ec6da78bab35
Eric Mc Sween 1 год назад
Родитель
Сommit
e4dae982d2

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

@@ -897,6 +897,10 @@
   "limited_document_history": "",
   "limited_offer": "",
   "limited_to_n_editors": "",
+  "limited_to_n_editors_or_reviewers": "",
+  "limited_to_n_editors_or_reviewers_per_project": "",
+  "limited_to_n_editors_or_reviewers_per_project_plural": "",
+  "limited_to_n_editors_or_reviewers_plural": "",
   "limited_to_n_editors_per_project": "",
   "limited_to_n_editors_per_project_plural": "",
   "limited_to_n_editors_plural": "",

+ 4 - 2
services/web/frontend/js/features/share-project-modal/components/add-collaborators.jsx

@@ -52,7 +52,7 @@ export default function AddCollaborators({ readOnly }) {
   const { reset, selectedItems } = multipleSelectionProps
 
   useEffect(() => {
-    if (readOnly && privileges === 'readAndWrite') {
+    if (readOnly && privileges !== 'readOnly') {
       setPrivileges('readOnly')
     }
   }, [privileges, readOnly])
@@ -171,7 +171,9 @@ export default function AddCollaborators({ readOnly }) {
               {t('can_edit')}
             </option>
             {getMeta('ol-isReviewerRoleEnabled') && (
-              <option value="review">{t('can_review')}</option>
+              <option disabled={readOnly} value="review">
+                {t('can_review')}
+              </option>
             )}
             <option value="readOnly">{t('can_view')}</option>
           </OLFormSelect>

+ 27 - 13
services/web/frontend/js/features/share-project-modal/components/edit-member.tsx

@@ -16,6 +16,7 @@ import OLCol from '@/features/ui/components/ol/ol-col'
 import MaterialIcon from '@/shared/components/material-icon'
 import getMeta from '@/utils/meta'
 import { useUserContext } from '@/shared/context/user-context'
+import { isSplitTestEnabled } from '@/utils/splitTestUtils'
 
 type PermissionsOption = PermissionsLevel | 'removeAccess' | 'downgraded'
 
@@ -249,28 +250,41 @@ function SelectPrivilege({
   }
 
   function getPrivilegeSubtitle(privilege: PermissionsOption) {
-    if (!hasBeenDowngraded) {
-      return !canAddCollaborators &&
-        privilege === 'readAndWrite' &&
-        value !== 'readAndWrite'
-        ? t('limited_to_n_editors_per_project', {
-            count: features.collaborators,
-          })
-        : ''
+    if (!['readAndWrite', 'review'].includes(privilege)) {
+      return ''
     }
 
-    return privilege === 'readAndWrite'
-      ? t('limited_to_n_editors', {
+    if (hasBeenDowngraded) {
+      if (isSplitTestEnabled('reviewer-role')) {
+        return t('limited_to_n_editors_or_reviewers', {
+          count: features.collaborators,
+        })
+      } else {
+        return t('limited_to_n_editors', { count: features.collaborators })
+      }
+    } else if (
+      !canAddCollaborators &&
+      !['readAndWrite', 'review'].includes(value)
+    ) {
+      if (isSplitTestEnabled('reviewer-role')) {
+        return t('limited_to_n_editors_or_reviewers_per_project', {
+          count: features.collaborators,
+        })
+      } else {
+        return t('limited_to_n_editors_per_project', {
           count: features.collaborators,
         })
-      : ''
+      }
+    } else {
+      return ''
+    }
   }
 
   function isPrivilegeDisabled(privilege: PermissionsOption) {
     return (
       !canAddCollaborators &&
-      privilege === 'readAndWrite' &&
-      (hasBeenDowngraded || value !== 'readAndWrite')
+      ['readAndWrite', 'review'].includes(privilege) &&
+      (hasBeenDowngraded || !['readAndWrite', 'review'].includes(value))
     )
   }
 

+ 3 - 3
services/web/frontend/js/features/share-project-modal/components/share-modal-body.tsx

@@ -27,11 +27,11 @@ export default function ShareModalBody() {
     }
 
     const editorInvites = invites.filter(
-      invite => invite.privileges === 'readAndWrite'
+      invite => invite.privileges !== 'readOnly'
     ).length
 
     return (
-      members.filter(member => member.privileges === 'readAndWrite').length +
+      members.filter(member => member.privileges !== 'readOnly').length +
         editorInvites <
       (features.collaborators ?? 1)
     )
@@ -67,7 +67,7 @@ export default function ShareModalBody() {
     }
 
     return (
-      members.filter(member => member.privileges === 'readAndWrite').length >
+      members.filter(member => member.privileges !== 'readOnly').length >
       (features.collaborators ?? 1)
     )
   }, [features, isProjectOwner, members])

+ 1 - 1
services/web/frontend/js/shared/context/types/project-context.tsx

@@ -4,7 +4,7 @@ import { ProjectSnapshot } from '@/infrastructure/project-snapshot'
 
 export type ProjectContextMember = {
   _id: UserId
-  privileges: 'readOnly' | 'readAndWrite'
+  privileges: 'readOnly' | 'readAndWrite' | 'review'
   email: string
   first_name: string
   last_name: string

+ 4 - 0
services/web/locales/en.json

@@ -1180,6 +1180,10 @@
   "license": "License",
   "limited_document_history": "Limited document history",
   "limited_to_n_editors": "Limited to __count__ editor",
+  "limited_to_n_editors_or_reviewers": "Limited to __count__ editor or reviewer",
+  "limited_to_n_editors_or_reviewers_per_project": "Limited to __count__ editor or reviewer per project",
+  "limited_to_n_editors_or_reviewers_per_project_plural": "Limited to __count__ editors or reviewers per project",
+  "limited_to_n_editors_or_reviewers_plural": "Limited to __count__ editors or reviewers",
   "limited_to_n_editors_per_project": "Limited to __count__ editor per project",
   "limited_to_n_editors_per_project_plural": "Limited to __count__ editors per project",
   "limited_to_n_editors_plural": "Limited to __count__ editors",

+ 34 - 0
services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.jsx

@@ -101,6 +101,7 @@ describe('<ShareProjectModal/>', function () {
     fetchMock.get('/user/contacts', { contacts })
     window.metaAttributesCache.set('ol-user', { allowedFreeTrial: true })
     window.metaAttributesCache.set('ol-showUpgradePrompt', true)
+    window.metaAttributesCache.set('ol-isReviewerRoleEnabled', true)
   })
 
   afterEach(function () {
@@ -691,6 +692,39 @@ describe('<ShareProjectModal/>', function () {
 
     await screen.findByText('Add more editors')
     expect(screen.getByRole('option', { name: 'Can edit' }).disabled).to.be.true
+    expect(screen.getByRole('option', { name: 'Can review' }).disabled).to.be
+      .true
+    expect(screen.getByRole('option', { name: 'Can view' }).disabled).to.be
+      .false
+
+    screen.getByText(
+      /Upgrade to add more editors and access collaboration features like track changes and full project history/
+    )
+  })
+
+  it('counts reviewers towards the collaborator limit', async function () {
+    renderWithEditorContext(<ShareProjectModal {...modalProps} />, {
+      scope: {
+        project: {
+          ...project,
+          features: {
+            collaborators: 1,
+          },
+          members: [
+            {
+              _id: 'reviewer-id',
+              email: 'reviewer@example.com',
+              privileges: 'review',
+            },
+          ],
+        },
+      },
+    })
+
+    await screen.findByText('Add more editors')
+    expect(screen.getByRole('option', { name: 'Can edit' }).disabled).to.be.true
+    expect(screen.getByRole('option', { name: 'Can review' }).disabled).to.be
+      .true
     expect(screen.getByRole('option', { name: 'Can view' }).disabled).to.be
       .false