From d5adc6ee4bf60eab8f219873cf7debddc2a03fdb Mon Sep 17 00:00:00 2001 From: ilkin-overleaf <100852799+ilkin-overleaf@users.noreply.github.com> Date: Thu, 27 Feb 2025 11:12:45 +0200 Subject: [PATCH] Merge pull request #23806 from overleaf/ii-bs5-manage-group-managers [web] BS5 Group managers management GitOrigin-RevId: 912fd29c3d5cf07eab0cd67e2771e60b1ba25fb3 --- .../UserMembershipController.mjs | 2 + .../user_membership/group-managers-react.pug | 4 + .../institution-managers-react.pug | 4 + .../publisher-managers-react.pug | 4 + .../components/managers-table.tsx | 217 ++++++++++-------- .../group-management/components/user-row.tsx | 116 ++++++---- .../bootstrap-5/components/group-members.scss | 8 + .../stylesheets/components/group-members.less | 8 + .../components/group-managers.spec.tsx | 140 ++++++----- .../components/institution-managers.spec.tsx | 140 ++++++----- .../components/publisher-managers.spec.tsx | 134 ++++++----- 11 files changed, 461 insertions(+), 316 deletions(-) diff --git a/services/web/app/src/Features/UserMembership/UserMembershipController.mjs b/services/web/app/src/Features/UserMembership/UserMembershipController.mjs index 3fa0f57a74..547b3ba854 100644 --- a/services/web/app/src/Features/UserMembership/UserMembershipController.mjs +++ b/services/web/app/src/Features/UserMembership/UserMembershipController.mjs @@ -120,6 +120,8 @@ async function _renderManagersPage(req, res, next, template) { entityConfig ) + await SplitTestHandler.promises.getAssignment(req, res, 'bootstrap-5-groups') + res.render(template, { name: entityName, users, diff --git a/services/web/app/views/user_membership/group-managers-react.pug b/services/web/app/views/user_membership/group-managers-react.pug index f4d8c0e973..143e2218d8 100644 --- a/services/web/app/views/user_membership/group-managers-react.pug +++ b/services/web/app/views/user_membership/group-managers-react.pug @@ -3,6 +3,10 @@ extends ../layout-marketing block entrypointVar - entrypoint = 'pages/user/subscription/group-management/group-managers' +block vars + - bootstrap5PageStatus = 'enabled' // One of 'disabled', 'enabled', and 'queryStringOnly' + - bootstrap5PageSplitTest = 'bootstrap-5-groups' + block append meta meta(name="ol-users", data-type="json", content=users) meta(name="ol-groupId", data-type="string", content=groupId) diff --git a/services/web/app/views/user_membership/institution-managers-react.pug b/services/web/app/views/user_membership/institution-managers-react.pug index 690e8409f2..99307f69a9 100644 --- a/services/web/app/views/user_membership/institution-managers-react.pug +++ b/services/web/app/views/user_membership/institution-managers-react.pug @@ -3,6 +3,10 @@ extends ../layout-marketing block entrypointVar - entrypoint = 'pages/user/subscription/group-management/institution-managers' +block vars + - bootstrap5PageStatus = 'enabled' // One of 'disabled', 'enabled', and 'queryStringOnly' + - bootstrap5PageSplitTest = 'bootstrap-5-groups' + block append meta meta(name="ol-users", data-type="json", content=users) meta(name="ol-groupId", data-type="string", content=groupId) diff --git a/services/web/app/views/user_membership/publisher-managers-react.pug b/services/web/app/views/user_membership/publisher-managers-react.pug index 793bdf9602..7f965add73 100644 --- a/services/web/app/views/user_membership/publisher-managers-react.pug +++ b/services/web/app/views/user_membership/publisher-managers-react.pug @@ -3,6 +3,10 @@ extends ../layout-marketing block entrypointVar - entrypoint = 'pages/user/subscription/group-management/publisher-managers' +block vars + - bootstrap5PageStatus = 'enabled' // One of 'disabled', 'enabled', and 'queryStringOnly' + - bootstrap5PageSplitTest = 'bootstrap-5-groups' + block append meta meta(name="ol-users", data-type="json", content=users) meta(name="ol-groupId", data-type="string", content=groupId) diff --git a/services/web/frontend/js/features/group-management/components/managers-table.tsx b/services/web/frontend/js/features/group-management/components/managers-table.tsx index 6eff6c522c..d5950f6578 100644 --- a/services/web/frontend/js/features/group-management/components/managers-table.tsx +++ b/services/web/frontend/js/features/group-management/components/managers-table.tsx @@ -1,9 +1,6 @@ import { useCallback, useState } from 'react' -import { Button, Col, Form, FormControl, Row } from 'react-bootstrap' import { useTranslation } from 'react-i18next' import { deleteJSON, FetchError, postJSON } from '@/infrastructure/fetch-json' -import MaterialIcon from '../../../shared/components/material-icon' -import Tooltip from '../../../shared/components/tooltip' import getMeta from '../../../utils/meta' import { parseEmails } from '../utils/emails' import ErrorAlert, { APIError } from './error-alert' @@ -11,6 +8,17 @@ import UserRow from './user-row' import useUserSelection from '../hooks/use-user-selection' import { User } from '../../../../../types/group-management/user' import { debugConsole } from '@/utils/debugging' +import OLRow from '@/features/ui/components/ol/ol-row' +import OLCol from '@/features/ui/components/ol/ol-col' +import BackButton from '@/features/group-management/components/back-button' +import OLCard from '@/features/ui/components/ol/ol-card' +import OLButton from '@/features/ui/components/ol/ol-button' +import OLFormControl from '@/features/ui/components/ol/ol-form-control' +import OLFormText from '@/features/ui/components/ol/ol-form-text' +import OLTable from '@/features/ui/components/ol/ol-table' +import OLTooltip from '@/features/ui/components/ol/ol-tooltip' +import OLFormCheckbox from '@/features/ui/components/ol/ol-form-checkbox' +import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher' type ManagersPaths = { addMember: string @@ -132,136 +140,155 @@ export function ManagersTable({ return (
- - -

- - - {' '} - {groupName || translations.title} -

-
-
+ + +
+ +

{groupName || translations.title}

+
+ +
{removeMemberInflightCount > 0 ? ( - + ) : ( <> {selectedUsers.length > 0 && ( - + )} )}
-

{translations.subtitle}

+

{translations.subtitle}

-
    -
  • - - - - + + + + + } + bs5={ + + } /> - {t('email')} - - - {t('name')} - - - + {t('email')} + {t('name')} + + - + {t('last_active')} (?) - - - - {t('accepted_invite')} - - -
  • - {users.length === 0 && ( -
  • - - + + + + {t('accepted_invite')} + + + + + {users.length === 0 && ( + + {t('no_members')} - - -
  • - )} - {users.map(user => ( - - ))} -
+ + + )} + {users.map(user => ( + + ))} + +

{t('add_more_managers')}

-
- - - + + + - - - {inviteUserInflightCount > 0 ? ( - - ) : ( - - )} - - - - - + + + 0} + bs3Props={{ + loading: + inviteUserInflightCount > 0 ? ( + <>{t('adding')}… + ) : ( + t('add') + ), + }} + > + {t('add')} + + + + + + {t('add_comma_separated_emails_help')} - - - -
+ + + +
-
- - + + +
) } diff --git a/services/web/frontend/js/features/group-management/components/user-row.tsx b/services/web/frontend/js/features/group-management/components/user-row.tsx index 99d93e93b6..fd7fea4b53 100644 --- a/services/web/frontend/js/features/group-management/components/user-row.tsx +++ b/services/web/frontend/js/features/group-management/components/user-row.tsx @@ -1,8 +1,11 @@ import moment from 'moment' import { useCallback } from 'react' -import { Col, Row } from 'react-bootstrap' import { useTranslation } from 'react-i18next' import { User } from '../../../../../types/group-management/user' +import OLFormCheckbox from '@/features/ui/components/ol/ol-form-checkbox' +import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher' +import Icon from '@/shared/components/icon' +import MaterialIcon from '@/shared/components/material-icon' type GroupMemberRowProps = { user: User @@ -31,52 +34,75 @@ export default function UserRow({ ) return ( -
  • - - - - handleSelectUser(e, user)} + + + handleSelectUser(e, user)} + aria-label={t('select_user')} + data-testid="select-single-checkbox" + /> + } + bs5={ + handleSelectUser(e, user)} + aria-label={t('select_user')} + data-testid="select-single-checkbox" + /> + } + /> + + {user.email} + + {user.first_name} {user.last_name} + + + {user.last_active_at + ? moment(user.last_active_at).format('Do MMM YYYY') + : 'N/A'} + + + {user.invite ? ( + + } + bs5={ + + } /> - {user.email} - - - {user.first_name} {user.last_name} - - - {user.last_active_at - ? moment(user.last_active_at).format('Do MMM YYYY') - : 'N/A'} - - - {user.invite ? ( - <> -