mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-12 05:36:40 +00:00
Merge pull request #14311 from overleaf/mf-resend-surrender-email
[web] Add an option to resend managed users invite in managed users setting GitOrigin-RevId: 2734ef3be31f77c309caec96e97411c9d48a8160
This commit is contained in:
parent
808fd2c0f9
commit
1e4028d05e
13 changed files with 366 additions and 31 deletions
|
@ -443,14 +443,22 @@ templates.surrenderAccountForManagedUsers = ctaTemplate({
|
|||
|
||||
const toGroupName = opts.groupName ? ` to ${opts.groupName}` : ''
|
||||
|
||||
return `You’ve been invited by ${admin} to transfer management of your ${settings.appName} account${toGroupName}`
|
||||
return `${
|
||||
opts.reminder ? 'Reminder: ' : ''
|
||||
}You’ve been invited by ${admin} to transfer management of your ${
|
||||
settings.appName
|
||||
} account${toGroupName}`
|
||||
},
|
||||
title(opts) {
|
||||
const admin = _.escape(_formatUserNameAndEmail(opts.admin, 'an admin'))
|
||||
|
||||
const toGroupName = opts.groupName ? ` to ${opts.groupName}` : ''
|
||||
|
||||
return `You’ve been invited by ${admin} to transfer management of your ${settings.appName} account${toGroupName}`
|
||||
return `${
|
||||
opts.reminder ? 'Reminder: ' : ''
|
||||
}You’ve been invited by ${admin} to transfer management of your ${
|
||||
settings.appName
|
||||
} account${toGroupName}`
|
||||
},
|
||||
message(opts, isPlainText) {
|
||||
const admin = _.escape(_formatUserNameAndEmail(opts.admin, 'an admin'))
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
"all_projects": "",
|
||||
"all_projects_will_be_transferred_immediately": "",
|
||||
"also": "",
|
||||
"an_email_has_already_been_sent_to": "",
|
||||
"an_error_occurred_when_verifying_the_coupon_code": "",
|
||||
"anonymous": "",
|
||||
"anyone_with_link_can_edit": "",
|
||||
|
@ -304,6 +305,7 @@
|
|||
"expires": "",
|
||||
"export_csv": "",
|
||||
"export_project_to_github": "",
|
||||
"failed_to_send_managed_user_invite_to_email": "",
|
||||
"fast": "",
|
||||
"faster_compiles_feedback_question": "",
|
||||
"faster_compiles_feedback_seems_faster": "",
|
||||
|
@ -589,6 +591,7 @@
|
|||
"manage_sessions": "",
|
||||
"manage_subscription": "",
|
||||
"managed": "",
|
||||
"managed_user_invite_has_been_sent_to_email": "",
|
||||
"managed_users": "",
|
||||
"managed_users_explanation": "",
|
||||
"managed_users_terms": "",
|
||||
|
@ -841,6 +844,7 @@
|
|||
"resend": "",
|
||||
"resend_confirmation_email": "",
|
||||
"resend_email": "",
|
||||
"resend_managed_user_invite": "",
|
||||
"resending_confirmation_email": "",
|
||||
"resolve": "",
|
||||
"resolved_comments": "",
|
||||
|
|
|
@ -1,21 +1,88 @@
|
|||
import {
|
||||
useState,
|
||||
type ComponentProps,
|
||||
useCallback,
|
||||
type Dispatch,
|
||||
type SetStateAction,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Dropdown, MenuItem } from 'react-bootstrap'
|
||||
import { User } from '../../../../../../types/group-management/user'
|
||||
import ControlledDropdown from '../../../../shared/components/controlled-dropdown'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import MenuItemButton from '../../../project-list/components/dropdown/menu-item-button'
|
||||
import useAsync from '../../../../shared/hooks/use-async'
|
||||
import {
|
||||
type FetchError,
|
||||
postJSON,
|
||||
} from '../../../../infrastructure/fetch-json'
|
||||
import Icon from '../../../../shared/components/icon'
|
||||
import { ManagedUserAlert } from '../../utils/types'
|
||||
import { useGroupMembersContext } from '../../context/group-members-context'
|
||||
|
||||
type ResendManagedUserInviteResponse = {
|
||||
success: boolean
|
||||
}
|
||||
|
||||
type ManagedUserDropdownButtonProps = {
|
||||
user: User
|
||||
openOffboardingModalForUser: (user: User) => void
|
||||
groupId: string
|
||||
setManagedUserAlert: Dispatch<SetStateAction<ManagedUserAlert>>
|
||||
}
|
||||
|
||||
export default function ManagedUserDropdownButton({
|
||||
user,
|
||||
openOffboardingModalForUser,
|
||||
groupId,
|
||||
setManagedUserAlert,
|
||||
}: ManagedUserDropdownButtonProps) {
|
||||
const { t } = useTranslation()
|
||||
const { removeMember } = useGroupMembersContext()
|
||||
const [isOpened, setIsOpened] = useState(false)
|
||||
const {
|
||||
runAsync: runResendManagedUserInviteAsync,
|
||||
isLoading: isResendingManagedUserInvite,
|
||||
} = useAsync<ResendManagedUserInviteResponse>()
|
||||
|
||||
const userNotManaged =
|
||||
!user.isEntityAdmin && !user.invite && !user.enrollment?.managedBy
|
||||
|
||||
const handleResendManagedUserInvite = useCallback(
|
||||
async user => {
|
||||
try {
|
||||
const result = await runResendManagedUserInviteAsync(
|
||||
postJSON(
|
||||
`/manage/groups/${groupId}/resendManagedUserInvite/${user._id}`
|
||||
)
|
||||
)
|
||||
|
||||
if (result.success) {
|
||||
setManagedUserAlert({
|
||||
variant: 'resendManagedUserInviteSuccess',
|
||||
email: user.email,
|
||||
})
|
||||
setIsOpened(false)
|
||||
}
|
||||
} catch (err) {
|
||||
if ((err as FetchError)?.response?.status === 429) {
|
||||
setManagedUserAlert({
|
||||
variant: 'resendManagedUserInviteTooManyRequests',
|
||||
email: user.email,
|
||||
})
|
||||
} else {
|
||||
setManagedUserAlert({
|
||||
variant: 'resendManagedUserInviteFailed',
|
||||
email: user.email,
|
||||
})
|
||||
}
|
||||
|
||||
setIsOpened(false)
|
||||
}
|
||||
},
|
||||
[setManagedUserAlert, groupId, runResendManagedUserInviteAsync]
|
||||
)
|
||||
|
||||
const onResendManagedUserInviteClick = () => {
|
||||
handleResendManagedUserInvite(user)
|
||||
}
|
||||
|
||||
const onDeleteUserClick = () => {
|
||||
openOffboardingModalForUser(user)
|
||||
|
@ -27,7 +94,11 @@ export default function ManagedUserDropdownButton({
|
|||
|
||||
return (
|
||||
<span className="managed-user-actions">
|
||||
<ControlledDropdown id={`managed-user-dropdown-${user.email}`}>
|
||||
<Dropdown
|
||||
id={`managed-user-dropdown-${user.email}`}
|
||||
open={isOpened}
|
||||
onToggle={open => setIsOpened(open)}
|
||||
>
|
||||
<Dropdown.Toggle
|
||||
bsStyle={null}
|
||||
className="btn btn-link action-btn"
|
||||
|
@ -39,7 +110,15 @@ export default function ManagedUserDropdownButton({
|
|||
aria-label={t('actions')}
|
||||
/>
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu className="dropdown-menu-right managed-users-dropdown-menu">
|
||||
<Dropdown.Menu className="dropdown-menu-right managed-user-dropdown-menu">
|
||||
{userNotManaged ? (
|
||||
<MenuItemButton onClick={onResendManagedUserInviteClick}>
|
||||
{t('resend_managed_user_invite')}
|
||||
{isResendingManagedUserInvite ? (
|
||||
<Icon type="spinner" spin style={{ marginLeft: '5px' }} />
|
||||
) : null}
|
||||
</MenuItemButton>
|
||||
) : null}
|
||||
{user.enrollment ? (
|
||||
<MenuItemButton
|
||||
className="delete-user-action"
|
||||
|
@ -62,7 +141,27 @@ export default function ManagedUserDropdownButton({
|
|||
</MenuItemButton>
|
||||
)}
|
||||
</Dropdown.Menu>
|
||||
</ControlledDropdown>
|
||||
</Dropdown>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
function MenuItemButton({
|
||||
children,
|
||||
onClick,
|
||||
className,
|
||||
...buttonProps
|
||||
}: ComponentProps<'button'>) {
|
||||
return (
|
||||
<li role="presentation" className={className}>
|
||||
<button
|
||||
className="managed-user-menu-item-button"
|
||||
role="menuitem"
|
||||
onClick={onClick}
|
||||
{...buttonProps}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,22 +1,27 @@
|
|||
import moment from 'moment'
|
||||
import { useCallback } from 'react'
|
||||
import { type Dispatch, type SetStateAction, useCallback } from 'react'
|
||||
import { Col, Row } from 'react-bootstrap'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { User } from '../../../../../../types/group-management/user'
|
||||
import Badge from '../../../../shared/components/badge'
|
||||
import { useGroupMembersContext } from '../../context/group-members-context'
|
||||
import ManagedUserDropdownButton from './managed-user-dropdown-button'
|
||||
import Tooltip from '../../../../shared/components/tooltip'
|
||||
import type { ManagedUserAlert } from '../../utils/types'
|
||||
import { useGroupMembersContext } from '../../context/group-members-context'
|
||||
import ManagedUserStatus from './managed-user-status'
|
||||
import ManagedUserDropdownButton from './managed-user-dropdown-button'
|
||||
|
||||
type ManagedUserRowProps = {
|
||||
user: User
|
||||
openOffboardingModalForUser: (user: User) => void
|
||||
groupId: string
|
||||
setManagedUserAlert: Dispatch<SetStateAction<ManagedUserAlert>>
|
||||
}
|
||||
|
||||
export default function ManagedUserRow({
|
||||
user,
|
||||
openOffboardingModalForUser,
|
||||
setManagedUserAlert,
|
||||
groupId,
|
||||
}: ManagedUserRowProps) {
|
||||
const { t } = useTranslation()
|
||||
const { selectedUsers, selectUser, unselectUser } = useGroupMembersContext()
|
||||
|
@ -101,6 +106,8 @@ export default function ManagedUserRow({
|
|||
<ManagedUserDropdownButton
|
||||
user={user}
|
||||
openOffboardingModalForUser={openOffboardingModalForUser}
|
||||
setManagedUserAlert={setManagedUserAlert}
|
||||
groupId={groupId}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
import { type PropsWithChildren, useState } from 'react'
|
||||
import { Alert, type AlertProps } from 'react-bootstrap'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import type { ManagedUserAlertVariant } from '../../utils/types'
|
||||
|
||||
type ManagedUsersListAlertProps = {
|
||||
variant: ManagedUserAlertVariant
|
||||
invitedUserEmail?: string
|
||||
onDismiss: () => void
|
||||
}
|
||||
|
||||
export default function ManagedUsersListAlert({
|
||||
variant,
|
||||
invitedUserEmail,
|
||||
onDismiss,
|
||||
}: ManagedUsersListAlertProps) {
|
||||
switch (variant) {
|
||||
case 'resendManagedUserInviteSuccess':
|
||||
return (
|
||||
<ResendManagedUserInviteSuccess
|
||||
onDismiss={onDismiss}
|
||||
invitedUserEmail={invitedUserEmail}
|
||||
/>
|
||||
)
|
||||
case 'resendManagedUserInviteFailed':
|
||||
return (
|
||||
<FailedToResendManagedInvite
|
||||
onDismiss={onDismiss}
|
||||
invitedUserEmail={invitedUserEmail}
|
||||
/>
|
||||
)
|
||||
case 'resendManagedUserInviteTooManyRequests':
|
||||
return (
|
||||
<TooManyRequests
|
||||
onDismiss={onDismiss}
|
||||
invitedUserEmail={invitedUserEmail}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
type ManagedUsersListAlertComponentProps = {
|
||||
onDismiss: () => void
|
||||
invitedUserEmail?: string
|
||||
}
|
||||
|
||||
function ResendManagedUserInviteSuccess({
|
||||
onDismiss,
|
||||
invitedUserEmail,
|
||||
}: ManagedUsersListAlertComponentProps) {
|
||||
return (
|
||||
<AlertComponent bsStyle="success" onDismiss={onDismiss}>
|
||||
<Trans
|
||||
i18nKey="managed_user_invite_has_been_sent_to_email"
|
||||
values={{
|
||||
email: invitedUserEmail,
|
||||
}}
|
||||
components={[
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<strong />,
|
||||
]}
|
||||
/>
|
||||
</AlertComponent>
|
||||
)
|
||||
}
|
||||
|
||||
function FailedToResendManagedInvite({
|
||||
onDismiss,
|
||||
invitedUserEmail,
|
||||
}: ManagedUsersListAlertComponentProps) {
|
||||
return (
|
||||
<AlertComponent bsStyle="danger" onDismiss={onDismiss}>
|
||||
<Trans
|
||||
i18nKey="failed_to_send_managed_user_invite_to_email"
|
||||
values={{
|
||||
email: invitedUserEmail,
|
||||
}}
|
||||
components={[
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<strong />,
|
||||
]}
|
||||
/>
|
||||
</AlertComponent>
|
||||
)
|
||||
}
|
||||
|
||||
function TooManyRequests({
|
||||
onDismiss,
|
||||
invitedUserEmail,
|
||||
}: ManagedUsersListAlertComponentProps) {
|
||||
return (
|
||||
<AlertComponent bsStyle="danger" onDismiss={onDismiss}>
|
||||
<Trans
|
||||
i18nKey="an_email_has_already_been_sent_to"
|
||||
values={{
|
||||
email: invitedUserEmail,
|
||||
}}
|
||||
components={[
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<strong />,
|
||||
]}
|
||||
/>
|
||||
</AlertComponent>
|
||||
)
|
||||
}
|
||||
|
||||
type AlertComponentProps = PropsWithChildren<{
|
||||
bsStyle: AlertProps['bsStyle']
|
||||
onDismiss: AlertProps['onDismiss']
|
||||
}>
|
||||
|
||||
function AlertComponent({ bsStyle, onDismiss, children }: AlertComponentProps) {
|
||||
const [show, setShow] = useState(true)
|
||||
const { t } = useTranslation()
|
||||
|
||||
const handleDismiss = () => {
|
||||
if (onDismiss) {
|
||||
onDismiss()
|
||||
}
|
||||
|
||||
setShow(false)
|
||||
}
|
||||
|
||||
if (!show) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Alert bsStyle={bsStyle} className="managed-users-list-alert">
|
||||
<span>{children}</span>
|
||||
<div className="managed-users-list-alert-close">
|
||||
<button type="button" className="close" onClick={handleDismiss}>
|
||||
<span aria-hidden="true">×</span>
|
||||
<span className="sr-only">{t('close')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</Alert>
|
||||
)
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
import { useState } from 'react'
|
||||
import { Col, Row } from 'react-bootstrap'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { User } from '../../../../../../types/group-management/user'
|
||||
import Tooltip from '../../../../shared/components/tooltip'
|
||||
import { useGroupMembersContext } from '../../context/group-members-context'
|
||||
import type { ManagedUserAlert } from '../../utils/types'
|
||||
import ManagedUserRow from './managed-user-row'
|
||||
import OffboardManagedUserModal from './offboard-managed-user-modal'
|
||||
import { useState } from 'react'
|
||||
import ManagedUsersListAlert from './managed-users-list-alert'
|
||||
|
||||
type ManagedUsersListProps = {
|
||||
handleSelectAllClick: (e: any) => void
|
||||
|
@ -20,10 +22,19 @@ export default function ManagedUsersList({
|
|||
const [userToOffboard, setUserToOffboard] = useState<User | undefined>(
|
||||
undefined
|
||||
)
|
||||
const [managedUserAlert, setManagedUserAlert] =
|
||||
useState<ManagedUserAlert>(undefined)
|
||||
const { selectedUsers, users } = useGroupMembersContext()
|
||||
|
||||
return (
|
||||
<div>
|
||||
{managedUserAlert && (
|
||||
<ManagedUsersListAlert
|
||||
variant={managedUserAlert.variant}
|
||||
invitedUserEmail={managedUserAlert.email}
|
||||
onDismiss={() => setManagedUserAlert(undefined)}
|
||||
/>
|
||||
)}
|
||||
<ul className="list-unstyled structured-list managed-users-list">
|
||||
<li className="container-fluid">
|
||||
<Row id="managed-users-list-headers">
|
||||
|
@ -76,6 +87,8 @@ export default function ManagedUsersList({
|
|||
key={user.email}
|
||||
user={user}
|
||||
openOffboardingModalForUser={setUserToOffboard}
|
||||
setManagedUserAlert={setManagedUserAlert}
|
||||
groupId={groupId}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
export type ManagedUserAlertVariant =
|
||||
| 'resendManagedUserInviteSuccess'
|
||||
| 'resendManagedUserInviteFailed'
|
||||
| 'resendManagedUserInviteTooManyRequests'
|
||||
|
||||
export type ManagedUserAlert =
|
||||
| {
|
||||
variant: ManagedUserAlertVariant
|
||||
email?: string
|
||||
}
|
||||
| undefined
|
|
@ -437,7 +437,7 @@ ul.structured-list {
|
|||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
-ms-overflow-style: -ms-autohiding-scrollbar;
|
||||
li {
|
||||
> li {
|
||||
border-bottom: 1px solid @structured-list-border-color;
|
||||
padding: (@line-height-computed / 4) 0;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
.managed-user-row {
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.managed-user-security {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
@ -30,15 +31,45 @@
|
|||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
li > button {
|
||||
&:hover {
|
||||
background-color: @gray-lightest;
|
||||
.managed-user-dropdown-menu {
|
||||
width: 300px;
|
||||
|
||||
li > button {
|
||||
&:hover {
|
||||
background-color: @gray-lightest;
|
||||
}
|
||||
}
|
||||
}
|
||||
.delete-user-action {
|
||||
button {
|
||||
color: @red;
|
||||
.delete-user-action {
|
||||
button {
|
||||
color: @red;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.managed-user-menu-item-button {
|
||||
padding: 12px 20px;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
background: inherit;
|
||||
color: @ol-blue-gray-5;
|
||||
text-align: left;
|
||||
&[disabled] {
|
||||
background-color: @gray-lighter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.managed-users-list-alert {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.managed-users-list-alert-close {
|
||||
padding-left: @padding-sm;
|
||||
text-align: right;
|
||||
width: 10%;
|
||||
@media (min-width: @screen-sm-min) {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,6 +95,7 @@
|
|||
"also": "Also",
|
||||
"also_available_as_on_premises": "Also available as On-Premises",
|
||||
"alternatively_create_new_institution_account": "Alternatively, you can create a <b>new account</b> with your institution email (<b>__email__</b>) by clicking <b>__clickText__</b>.",
|
||||
"an_email_has_already_been_sent_to": "An email has already been sent to <0>__email__</0>. Please wait and try again later.",
|
||||
"an_error_occurred_when_verifying_the_coupon_code": "An error occurred when verifying the coupon code",
|
||||
"and": "and",
|
||||
"annual": "Annual",
|
||||
|
@ -484,6 +485,7 @@
|
|||
"expiry": "Expiry Date",
|
||||
"export_csv": "Export CSV",
|
||||
"export_project_to_github": "Export Project to GitHub",
|
||||
"failed_to_send_managed_user_invite_to_email": "Failed to send Managed User invite to <0>__email__</0>. Please try again later.",
|
||||
"faq_change_plans_or_cancel_answer": "Yes, you can do this at any time via your subscription settings. You can change plans, switch between monthly and annual billing options, or cancel to downgrade to the free plan. When cancelling, your subscription will continue until the end of the billing period. If your account temporarily does not have a subscription, the only change will be to the features available to you. Your projects will always be available on your account.",
|
||||
"faq_change_plans_or_cancel_question": "Can I change plans or cancel later?",
|
||||
"faq_do_collab_need_on_paid_plan_answer": "No, they can be on any plan, including the free plan. If you are on a premium plan, some premium features will be available to your collaborators in projects that you have created, even if those collaborators are on the free plan. For more information, read about <0>account and subscriptions</0> and <1>how premium features work</1>.",
|
||||
|
@ -968,6 +970,7 @@
|
|||
"manage_sessions": "Manage Your Sessions",
|
||||
"manage_subscription": "Manage Subscription",
|
||||
"managed": "Managed",
|
||||
"managed_user_invite_has_been_sent_to_email": "Managed User invite has been sent to <0>__email__</0>",
|
||||
"managed_users": "Managed Users",
|
||||
"managed_users_explanation": "Managed Users ensures you stay in control of your organization’s projects and who owns them. <0>Read more about Managed Users.</0>",
|
||||
"managed_users_terms": "To use the Managed Users feature, you must agree to the latest version of our customer terms at <0>__link__</0> on behalf of your organization by selecting \"I agree\" below. These terms will then apply to your organization’s use of Overleaf in place of any previously agreed Overleaf terms, except where we have a signed agreement in place with you, in which case that signed agreement will continue to govern. Please keep a copy for your records",
|
||||
|
@ -1376,6 +1379,7 @@
|
|||
"resend": "Resend",
|
||||
"resend_confirmation_email": "Resend confirmation email",
|
||||
"resend_email": "Resend email",
|
||||
"resend_managed_user_invite": "Resend Managed User invite",
|
||||
"resending_confirmation_email": "Resending confirmation email",
|
||||
"reset_password": "Reset Password",
|
||||
"reset_your_password": "Reset your password",
|
||||
|
@ -1809,6 +1813,7 @@
|
|||
"user_already_added": "User already added",
|
||||
"user_deletion_error": "Sorry, something went wrong deleting your account. Please try again in a minute.",
|
||||
"user_deletion_password_reset_tip": "If you cannot remember your password, or if you are using Single-Sign-On with another provider to sign in (such as Twitter or Google), please <0>reset your password</0> and try again.",
|
||||
"user_is_not_part_of_group": "User is not part of group",
|
||||
"user_management": "User management",
|
||||
"user_management_info": "Group plan admins have access to an admin panel where users can be added and removed easily. For site-wide plans, users are automatically upgraded when they register or add their email address to Overleaf (domain-based enrollment or SSO).",
|
||||
"user_not_found": "User not found",
|
||||
|
|
|
@ -64,7 +64,7 @@ describe('group members, with managed users', function () {
|
|||
cy.get('small').contains('You have added 3 of 10 available members')
|
||||
|
||||
cy.get('ul.managed-users-list').within(() => {
|
||||
cy.get('li:nth-child(2)').within(() => {
|
||||
cy.get('> li:nth-child(2)').within(() => {
|
||||
cy.contains('john.doe@test.com')
|
||||
cy.contains('John Doe')
|
||||
cy.contains('15th Jan 2023')
|
||||
|
@ -74,7 +74,7 @@ describe('group members, with managed users', function () {
|
|||
cy.get(`.security-state-invite-pending`).should('exist')
|
||||
})
|
||||
|
||||
cy.get('li:nth-child(3)').within(() => {
|
||||
cy.get('> li:nth-child(3)').within(() => {
|
||||
cy.contains('bobby.lapointe@test.com')
|
||||
cy.contains('Bobby Lapointe')
|
||||
cy.contains('2nd Jan 2023')
|
||||
|
@ -82,7 +82,7 @@ describe('group members, with managed users', function () {
|
|||
cy.get('i[aria-label="Not managed"]').should('exist')
|
||||
})
|
||||
|
||||
cy.get('li:nth-child(4)').within(() => {
|
||||
cy.get('> li:nth-child(4)').within(() => {
|
||||
cy.contains('claire.jennings@test.com')
|
||||
cy.contains('Claire Jennings')
|
||||
cy.contains('3rd Jan 2023')
|
||||
|
@ -107,7 +107,7 @@ describe('group members, with managed users', function () {
|
|||
cy.get('.add-more-members-form button').click()
|
||||
|
||||
cy.get('ul.managed-users-list').within(() => {
|
||||
cy.get('li:nth-child(5)').within(() => {
|
||||
cy.get('> li:nth-child(5)').within(() => {
|
||||
cy.contains('someone.else@test.com')
|
||||
cy.contains('N/A')
|
||||
cy.get(`[aria-label="Pending invite"]`)
|
||||
|
@ -134,7 +134,7 @@ describe('group members, with managed users', function () {
|
|||
|
||||
it('checks the select all checkbox', function () {
|
||||
cy.get('ul.managed-users-list').within(() => {
|
||||
cy.get('li:nth-child(2)').within(() => {
|
||||
cy.get('> li:nth-child(2)').within(() => {
|
||||
cy.get('.select-item').should('not.be.checked')
|
||||
})
|
||||
cy.get('li:nth-child(3)').within(() => {
|
||||
|
@ -145,7 +145,7 @@ describe('group members, with managed users', function () {
|
|||
cy.get('.select-all').click()
|
||||
|
||||
cy.get('ul.managed-users-list').within(() => {
|
||||
cy.get('li:nth-child(2)').within(() => {
|
||||
cy.get('> li:nth-child(2)').within(() => {
|
||||
cy.get('.select-item').should('be.checked')
|
||||
})
|
||||
cy.get('li:nth-child(3)').within(() => {
|
||||
|
@ -160,7 +160,7 @@ describe('group members, with managed users', function () {
|
|||
})
|
||||
|
||||
cy.get('ul.managed-users-list').within(() => {
|
||||
cy.get('li:nth-child(2)').within(() => {
|
||||
cy.get('> li:nth-child(2)').within(() => {
|
||||
cy.get('.select-item').check()
|
||||
})
|
||||
})
|
||||
|
@ -169,7 +169,7 @@ describe('group members, with managed users', function () {
|
|||
|
||||
cy.get('small').contains('You have added 2 of 10 available members')
|
||||
cy.get('ul.managed-users-list').within(() => {
|
||||
cy.get('li:nth-child(2)').within(() => {
|
||||
cy.get('> li:nth-child(2)').within(() => {
|
||||
cy.contains('bobby.lapointe@test.com')
|
||||
cy.contains('Bobby Lapointe')
|
||||
cy.contains('2nd Jan 2023')
|
||||
|
@ -184,7 +184,7 @@ describe('group members, with managed users', function () {
|
|||
|
||||
cy.get('ul.managed-users-list').within(() => {
|
||||
// Select 'Claire Jennings', a managed user
|
||||
cy.get('li:nth-child(4)').within(() => {
|
||||
cy.get('> li:nth-child(4)').within(() => {
|
||||
cy.get('.select-item').check()
|
||||
})
|
||||
})
|
||||
|
@ -201,7 +201,7 @@ describe('group members, with managed users', function () {
|
|||
|
||||
cy.get('ul.managed-users-list').within(() => {
|
||||
// Select 'Claire Jennings', a managed user
|
||||
cy.get('li:nth-child(4)').within(() => {
|
||||
cy.get('> li:nth-child(4)').within(() => {
|
||||
cy.get('.select-item').check()
|
||||
})
|
||||
// Select another user
|
||||
|
@ -221,7 +221,7 @@ describe('group members, with managed users', function () {
|
|||
})
|
||||
|
||||
cy.get('ul.managed-users-list').within(() => {
|
||||
cy.get('li:nth-child(2)').within(() => {
|
||||
cy.get('> li:nth-child(2)').within(() => {
|
||||
cy.get('.select-item').check()
|
||||
})
|
||||
})
|
||||
|
|
|
@ -3,6 +3,8 @@ import sinon from 'sinon'
|
|||
import { GroupMembersProvider } from '../../../../../../frontend/js/features/group-management/context/group-members-context'
|
||||
|
||||
describe('ManagedUserDropdownButton', function () {
|
||||
const subscriptionId = '123abc'
|
||||
|
||||
describe('with managed user', function () {
|
||||
const user = {
|
||||
_id: 'some-user',
|
||||
|
@ -28,6 +30,8 @@ describe('ManagedUserDropdownButton', function () {
|
|||
<ManagedUserDropdownButton
|
||||
user={user}
|
||||
openOffboardingModalForUser={sinon.stub()}
|
||||
groupId={subscriptionId}
|
||||
setManagedUserAlert={sinon.stub()}
|
||||
/>
|
||||
</GroupMembersProvider>
|
||||
)
|
||||
|
@ -71,6 +75,8 @@ describe('ManagedUserDropdownButton', function () {
|
|||
<ManagedUserDropdownButton
|
||||
user={user}
|
||||
openOffboardingModalForUser={sinon.stub()}
|
||||
groupId={subscriptionId}
|
||||
setManagedUserAlert={sinon.stub()}
|
||||
/>
|
||||
</GroupMembersProvider>
|
||||
)
|
||||
|
@ -114,6 +120,8 @@ describe('ManagedUserDropdownButton', function () {
|
|||
<ManagedUserDropdownButton
|
||||
user={user}
|
||||
openOffboardingModalForUser={sinon.stub()}
|
||||
groupId={subscriptionId}
|
||||
setManagedUserAlert={sinon.stub()}
|
||||
/>
|
||||
</GroupMembersProvider>
|
||||
)
|
||||
|
|
|
@ -4,6 +4,8 @@ import { GroupMembersProvider } from '../../../../../../frontend/js/features/gro
|
|||
import { User } from '../../../../../../types/group-management/user'
|
||||
|
||||
describe('ManagedUserRow', function () {
|
||||
const subscriptionId = '123abc'
|
||||
|
||||
describe('with an ordinary user', function () {
|
||||
let user: User
|
||||
|
||||
|
@ -27,6 +29,8 @@ describe('ManagedUserRow', function () {
|
|||
<ManagedUserRow
|
||||
user={user}
|
||||
openOffboardingModalForUser={sinon.stub()}
|
||||
groupId={subscriptionId}
|
||||
setManagedUserAlert={sinon.stub()}
|
||||
/>
|
||||
</GroupMembersProvider>
|
||||
)
|
||||
|
@ -75,6 +79,8 @@ describe('ManagedUserRow', function () {
|
|||
<ManagedUserRow
|
||||
user={user}
|
||||
openOffboardingModalForUser={sinon.stub()}
|
||||
groupId={subscriptionId}
|
||||
setManagedUserAlert={sinon.stub()}
|
||||
/>
|
||||
</GroupMembersProvider>
|
||||
)
|
||||
|
@ -108,6 +114,8 @@ describe('ManagedUserRow', function () {
|
|||
<ManagedUserRow
|
||||
user={user}
|
||||
openOffboardingModalForUser={sinon.stub()}
|
||||
groupId={subscriptionId}
|
||||
setManagedUserAlert={sinon.stub()}
|
||||
/>
|
||||
</GroupMembersProvider>
|
||||
)
|
||||
|
@ -141,6 +149,8 @@ describe('ManagedUserRow', function () {
|
|||
<ManagedUserRow
|
||||
user={user}
|
||||
openOffboardingModalForUser={sinon.stub()}
|
||||
groupId={subscriptionId}
|
||||
setManagedUserAlert={sinon.stub()}
|
||||
/>
|
||||
</GroupMembersProvider>
|
||||
)
|
||||
|
|
Loading…
Add table
Reference in a new issue