diff --git a/client/src/locales/en-US.json b/client/src/locales/en-US.json index 520c11b7340..145c66cea9c 100644 --- a/client/src/locales/en-US.json +++ b/client/src/locales/en-US.json @@ -319,7 +319,6 @@ } }, "WorkspaceSharing": { - "title": "Share this workspace", "searchPlaceholder": "e.g.: John Smith", "currentUserLabel": "Me", "unshareSuccess": "The workspace is no longer shared with {user}.", @@ -330,8 +329,21 @@ "alreadyNotShared": "This workspace is not shared with {user}.", "alreadyHasRole": "{user} is already {role} on this workspace." }, + "batchSharing": { + "outsiderRoleWarning": "{external} profiles can only have {contributor} or {reader} roles.", + "external": "External", + "contributor": "Contributor", + "reader": "Reader", + "buttonSelect": "Selection", + "buttonFinish": "Finish", + "chooseRole": "Choose a role", + "noChanges": "Selected members were already {role}.", + "someFailed": "Some role assignments failed.", + "updateRoleSuccess": "Selected members' roles have been updated to {role}.", + "unshareSuccess": "The workspace is no longer shared with selected members." + }, "onlyOwnerWarning": "To prevent data loss if you ever leave the organization, we recommend promoting someone else to {owner} on this workspace.", - "owner": "owner", + "owner": "Owner", "noMatch": "No user found that matches '{query}'." }, "SettingsModal": { diff --git a/client/src/locales/fr-FR.json b/client/src/locales/fr-FR.json index 505694a7fea..98b4fb971c1 100644 --- a/client/src/locales/fr-FR.json +++ b/client/src/locales/fr-FR.json @@ -319,7 +319,6 @@ } }, "WorkspaceSharing": { - "title": "Partager cet espace de travail", "searchPlaceholder": "ex : Jean Martin", "currentUserLabel": "Moi", "unshareSuccess": "L'espace de travail n'est plus partagé avec {user}.", @@ -330,8 +329,21 @@ "alreadyNotShared": "Cet espace de travail n'est pas partagé avec {user}.", "alreadyHasRole": "{user} est déjà {role} sur cet espace de travail." }, + "batchSharing": { + "outsiderRoleWarning": "Les profils {external} ne peuvent avoir que les rôles {contributor} ou {reader}.", + "external": "Externe", + "contributor": "Contributeur", + "reader": "Lecteur", + "buttonSelect": "Sélectionner", + "buttonFinish": "Terminer", + "chooseRole": "Choisir un rôle", + "noChanges": "Les membres sélectionnés étaient déjà {role}.", + "someFailed": "Certaines assignations de rôle ont échoué.", + "updateRoleSuccess": "Le rôle des membres sélectionnées est désormais {role}.", + "unshareSuccess": "L'espace de travail n'est plus partagé avec les membres sélectionnés." + }, "onlyOwnerWarning": "Nous vous recommandons de promouvoir quelqu'un d'autre au poste de {owner}. Vous éviterez ainsi de perdre des données si vous quittez l'organisation.", - "owner": "propriétaire", + "owner": "Propriétaire", "noMatch": "Aucun utilisateur trouvé qui correspond à la recherche '{query}'." }, "SettingsModal": { diff --git a/client/src/views/workspaces/WorkspaceSharingModal.vue b/client/src/views/workspaces/WorkspaceSharingModal.vue index e9a22de9819..9ab49604b60 100644 --- a/client/src/views/workspaces/WorkspaceSharingModal.vue +++ b/client/src/views/workspaces/WorkspaceSharingModal.vue @@ -3,23 +3,58 @@ @@ -334,7 +543,7 @@ async function updateUserRole( color: var(--parsec-color-light-secondary-hard-grey); } -.only-owner-warning { +.info-text { margin-bottom: 1rem; } @@ -381,5 +590,9 @@ async function updateUserRole( top: 0; z-index: 3; } + + .checkbox { + margin-right: 0.5rem; + } } diff --git a/client/tests/e2e/specs/workspace_sharing.spec.ts b/client/tests/e2e/specs/workspace_sharing.spec.ts index 56a2bddc931..1f12c171ec3 100644 --- a/client/tests/e2e/specs/workspace_sharing.spec.ts +++ b/client/tests/e2e/specs/workspace_sharing.spec.ts @@ -3,9 +3,8 @@ import { expect, fillIonInput, msTest } from '@tests/e2e/helpers'; msTest('Workspace sharing modal default state', async ({ workspaceSharingModal }) => { - await expect(workspaceSharingModal.locator('.ms-modal-header__title')).toHaveText('Share this workspace'); + await expect(workspaceSharingModal.locator('.ms-modal-header__title')).toHaveText('Trademeet'); const content = workspaceSharingModal.locator('.ms-modal-content'); - await expect(content.locator('.modal-title')).toHaveText('Trademeet'); await expect(content.locator('.only-owner-warning')).toBeVisible(); const users = content.locator('.user-list').locator('.content'); await expect(users).toHaveCount(3); @@ -93,3 +92,60 @@ msTest('Filter users no match', async ({ workspaceSharingModal }) => { await expect(content.locator('.no-match-result')).toBeVisible(); await expect(content.locator('.no-match-result')).toHaveText("No user found that matches 'nomatch'."); }); + +msTest('Batch workspace sharing', async ({ workspaceSharingModal }) => { + const content = workspaceSharingModal.locator('.ms-modal-content'); + const batchDropdown = content.locator('.modal-head-content').locator('.dropdown-container').locator('#dropdown-popover-button'); + const activateBatchButton = content.locator('#batch-activate-button'); + const membersCheckbox = content.locator('#all-members-checkbox'); + + await expect(content.locator('#profile-assign-info')).not.toBeVisible(); + await expect(batchDropdown).not.toBeVisible(); + await expect(activateBatchButton).toContainText('Selection'); + await expect(membersCheckbox).not.toBeVisible(); + + // Share with non-external users + await activateBatchButton.click(); + await expect(content.locator('#profile-assign-info')).toBeVisible(); + await expect(content.locator('#profile-assign-info')).toContainText('External profiles can only have Contributor or Reader roles.'); + await expect(batchDropdown).toBeVisible(); + await expect(batchDropdown).toBeTrulyDisabled(); + await expect(activateBatchButton).toContainText('Finish'); + await expect(membersCheckbox).toBeVisible(); + + await membersCheckbox.click(); + await batchDropdown.click(); + + const roleDropdown = workspaceSharingModal.page().locator('.dropdown-popover'); + const roles = roleDropdown.getByRole('listitem'); + await expect(roles.locator('.option-text__label')).toHaveText(['Owner', 'Manager', 'Contributor', 'Reader', 'Not shared']); + + await roles.nth(4).click(); + await expect(workspaceSharingModal.page()).toShowToast('The workspace is no longer shared with selected members.', 'Success'); + + await expect(content.locator('#profile-assign-info')).not.toBeVisible(); + await expect(batchDropdown).not.toBeVisible(); + await expect(activateBatchButton).toContainText('Selection'); + await expect(membersCheckbox).not.toBeVisible(); + + // Check external user restriction + await activateBatchButton.click(); + await content.locator('#member-checkbox').nth(0).click(); + await content.locator('#suggested-checkbox').nth(0).click(); + await expect(membersCheckbox).toHaveState('checked'); + await batchDropdown.click(); + await expect(roles.locator('.option-text__label')).toHaveText(['Owner', 'Manager', 'Contributor', 'Reader', 'Not shared']); + + for (const [index, role] of (await roles.all()).entries()) { + if (index === 0 || index === 1) { + await expect(role).toHaveTheClass('item-disabled'); + } else { + await expect(role).not.toHaveTheClass('item-disabled'); + } + } + await roles.nth(2).click(); + await expect(workspaceSharingModal.page()).toShowToast("Selected members' roles have been updated to Contributor.", 'Success'); + await expect(batchDropdown).not.toBeVisible(); + await expect(activateBatchButton).toContainText('Selection'); + await expect(membersCheckbox).not.toBeVisible(); +}); diff --git a/client/tests/e2e/specs/workspaces_actions.spec.ts b/client/tests/e2e/specs/workspaces_actions.spec.ts index 0978df3ab30..b6e7d715fbd 100644 --- a/client/tests/e2e/specs/workspaces_actions.spec.ts +++ b/client/tests/e2e/specs/workspaces_actions.spec.ts @@ -164,6 +164,6 @@ for (const mode of ['grid', 'list', 'sidebar']) { const popover = connected.locator('.workspace-context-menu'); await popover.getByRole('listitem').nth(5).click(); await expect(connected.locator('.workspace-sharing-modal')).toBeVisible(); - await expect(connected.locator('.workspace-sharing-modal').locator('.ms-modal-header__title')).toHaveText('Share this workspace'); + await expect(connected.locator('.workspace-sharing-modal').locator('.ms-modal-header__title')).toHaveText('Trademeet'); }); }