From c4bea21ee2c44d47e91334ae6e13c6cac54ef66a Mon Sep 17 00:00:00 2001 From: Alexandre Bourdin Date: Thu, 9 Nov 2023 17:26:46 +0100 Subject: [PATCH] Merge pull request #15669 from overleaf/ab-fix-sso-linking-status [web] Fix SSO status in group members table GitOrigin-RevId: e54e7b0c9640f0b96d9692c0208357e3bac2de91 --- .../UserMembership/UserMembershipViewModel.js | 1 + .../components/members-table/sso-status.tsx | 34 +++++++++++++----- .../components/group-members.spec.tsx | 35 +++++++++++-------- .../components/managed-group-members.spec.tsx | 27 ++++++++++---- .../members-table/dropdown-button.spec.tsx | 17 ++++++--- .../UserMembershipViewModelTests.js | 5 +++ services/web/types/group-management/user.ts | 8 ++++- 7 files changed, 92 insertions(+), 35 deletions(-) diff --git a/services/web/app/src/Features/UserMembership/UserMembershipViewModel.js b/services/web/app/src/Features/UserMembership/UserMembershipViewModel.js index 550f666312..8b90be3647 100644 --- a/services/web/app/src/Features/UserMembership/UserMembershipViewModel.js +++ b/services/web/app/src/Features/UserMembership/UserMembershipViewModel.js @@ -66,6 +66,7 @@ function buildUserViewModel(user, isInvite) { ? { managedBy: user.enrollment.managedBy, enrolledAt: user.enrollment.enrolledAt, + sso: user.enrollment.sso, } : undefined, } diff --git a/services/web/frontend/js/features/group-management/components/members-table/sso-status.tsx b/services/web/frontend/js/features/group-management/components/members-table/sso-status.tsx index ad3fbcd7e5..4a349d2f54 100644 --- a/services/web/frontend/js/features/group-management/components/members-table/sso-status.tsx +++ b/services/web/frontend/js/features/group-management/components/members-table/sso-status.tsx @@ -1,13 +1,27 @@ import { useTranslation } from 'react-i18next' +import getMeta from '@/utils/meta' import { User } from '../../../../../../types/group-management/user' import MaterialIcon from '@/shared/components/material-icon' type SSOStatusProps = { user: User } + export default function SSOStatus({ user }: SSOStatusProps) { + const groupId = getMeta('ol-groupId') + + if (user.invite) { + return + } + + const linkedSSO = user.enrollment?.sso?.some(sso => sso.groupId === groupId) + + return linkedSSO ? : +} + +function PendingInvite() { const { t } = useTranslation() - const invitedSSO = ( + return ( ) - const acceptedSSO = ( +} + +function SSOLinked() { + const { t } = useTranslation() + return (   {t('sso')} ) - const notAcceptedSSO = ( +} + +function SSOUnlinked() { + const { t } = useTranslation() + return (   {t('sso')} ) - - if (user.invite) { - return invitedSSO - } - - return user.enrollment?.sso ? acceptedSSO : notAcceptedSSO } diff --git a/services/web/test/frontend/features/group-management/components/group-members.spec.tsx b/services/web/test/frontend/features/group-management/components/group-members.spec.tsx index dd72bd04b8..8caeefe1f2 100644 --- a/services/web/test/frontend/features/group-management/components/group-members.spec.tsx +++ b/services/web/test/frontend/features/group-management/components/group-members.spec.tsx @@ -1,5 +1,6 @@ import GroupMembers from '@/features/group-management/components/group-members' import { GroupMembersProvider } from '@/features/group-management/context/group-members-context' +import { User } from '../../../../../types/group-management/user' const GROUP_ID = '777fff777fff' const PATHS = { @@ -173,7 +174,7 @@ describe('GroupMembers', function () { }) describe('with Managed Users enabled', function () { - const JOHN_DOE = { + const JOHN_DOE: User = { _id: 'abc123def456', first_name: 'John', last_name: 'Doe', @@ -181,7 +182,7 @@ describe('GroupMembers', function () { last_active_at: new Date('2023-01-15'), invite: true, } - const BOBBY_LAPOINTE = { + const BOBBY_LAPOINTE: User = { _id: 'bcd234efa567', first_name: 'Bobby', last_name: 'Lapointe', @@ -189,7 +190,7 @@ describe('GroupMembers', function () { last_active_at: new Date('2023-01-02'), invite: false, } - const CLAIRE_JENNINGS = { + const CLAIRE_JENNINGS: User = { _id: 'defabc231453', first_name: 'Claire', last_name: 'Jennings', @@ -199,10 +200,13 @@ describe('GroupMembers', function () { enrollment: { managedBy: GROUP_ID, enrolledAt: new Date('2023-01-03'), - sso: { - providerId: '123', - externalId: '123', - }, + sso: [ + { + groupId: GROUP_ID, + linkedAt: new Date(), + primary: true, + }, + ], }, } @@ -376,7 +380,7 @@ describe('GroupMembers', function () { }) describe('with Group SSO enabled', function () { - const JOHN_DOE = { + const JOHN_DOE: User = { _id: 'abc123def456', first_name: 'John', last_name: 'Doe', @@ -384,7 +388,7 @@ describe('GroupMembers', function () { last_active_at: new Date('2023-01-15'), invite: true, } - const BOBBY_LAPOINTE = { + const BOBBY_LAPOINTE: User = { _id: 'bcd234efa567', first_name: 'Bobby', last_name: 'Lapointe', @@ -392,7 +396,7 @@ describe('GroupMembers', function () { last_active_at: new Date('2023-01-02'), invite: false, } - const CLAIRE_JENNINGS = { + const CLAIRE_JENNINGS: User = { _id: 'defabc231453', first_name: 'Claire', last_name: 'Jennings', @@ -402,10 +406,13 @@ describe('GroupMembers', function () { enrollment: { managedBy: GROUP_ID, enrolledAt: new Date('2023-01-03'), - sso: { - providerId: '123', - externalId: '123', - }, + sso: [ + { + groupId: GROUP_ID, + linkedAt: new Date(), + primary: true, + }, + ], }, } diff --git a/services/web/test/frontend/features/group-management/components/managed-group-members.spec.tsx b/services/web/test/frontend/features/group-management/components/managed-group-members.spec.tsx index 11a9f86cd9..2cea99fe12 100644 --- a/services/web/test/frontend/features/group-management/components/managed-group-members.spec.tsx +++ b/services/web/test/frontend/features/group-management/components/managed-group-members.spec.tsx @@ -1,8 +1,9 @@ import GroupMembers from '@/features/group-management/components/group-members' import { GroupMembersProvider } from '@/features/group-management/context/group-members-context' +import { User } from '../../../../../types/group-management/user' const GROUP_ID = '777fff777fff' -const JOHN_DOE = { +const JOHN_DOE: User = { _id: 'abc123def456', first_name: 'John', last_name: 'Doe', @@ -10,15 +11,24 @@ const JOHN_DOE = { last_active_at: new Date('2023-01-15'), invite: true, } -const BOBBY_LAPOINTE = { +const BOBBY_LAPOINTE: User = { _id: 'bcd234efa567', first_name: 'Bobby', last_name: 'Lapointe', email: 'bobby.lapointe@test.com', last_active_at: new Date('2023-01-02'), invite: false, + enrollment: { + sso: [ + { + groupId: 'another', + linkedAt: new Date(), + primary: true, + }, + ], + }, } -const CLAIRE_JENNINGS = { +const CLAIRE_JENNINGS: User = { _id: 'defabc231453', first_name: 'Claire', last_name: 'Jennings', @@ -28,10 +38,13 @@ const CLAIRE_JENNINGS = { enrollment: { managedBy: GROUP_ID, enrolledAt: new Date('2023-01-03'), - sso: { - providerId: '123', - externalId: '123', - }, + sso: [ + { + groupId: GROUP_ID, + linkedAt: new Date(), + primary: true, + }, + ], }, } const PATHS = { diff --git a/services/web/test/frontend/features/group-management/components/members-table/dropdown-button.spec.tsx b/services/web/test/frontend/features/group-management/components/members-table/dropdown-button.spec.tsx index 564ebd4a5e..732d0c4e81 100644 --- a/services/web/test/frontend/features/group-management/components/members-table/dropdown-button.spec.tsx +++ b/services/web/test/frontend/features/group-management/components/members-table/dropdown-button.spec.tsx @@ -233,6 +233,7 @@ describe('ManagedUserDropdownButton', function () { }, isEntityAdmin: undefined, } + beforeEach(function () { cy.window().then(win => { win.metaAttributesCache.set('ol-users', [user]) @@ -241,11 +242,13 @@ describe('ManagedUserDropdownButton', function () { win.metaAttributesCache.set('ol-groupSSOActive', true) }) }) + it('should show resend invite when user is admin', function () { mountDropDownComponent({ ...user, isEntityAdmin: true }, '123abc') cy.get('.action-btn').click() cy.findByTestId('resend-sso-link-invite-action').should('exist') }) + it('should not show resend invite when SSO is disabled', function () { cy.window().then(win => { win.metaAttributesCache.set('ol-groupSSOActive', false) @@ -254,6 +257,7 @@ describe('ManagedUserDropdownButton', function () { cy.get('.action-btn').click() cy.findByTestId('resend-sso-link-invite-action').should('not.exist') }) + it('should not show resend invite when user has accepted SSO already', function () { cy.window().then(win => { win.metaAttributesCache.set('ol-groupSSOActive', false) @@ -264,10 +268,13 @@ describe('ManagedUserDropdownButton', function () { enrollment: { managedBy: 'some-group', enrolledAt: new Date(), - sso: { - providerId: '123', - externalId: '123', - }, + sso: [ + { + groupId: 'abc123abc123', + linkedAt: new Date(), + primary: true, + }, + ], }, }, '123abc' @@ -275,6 +282,7 @@ describe('ManagedUserDropdownButton', function () { cy.get('.action-btn').click() cy.findByTestId('resend-sso-link-invite-action').should('not.exist') }) + it('should show the resend SSO invite option when dropdown button is clicked', function () { cy.window().then(win => { win.metaAttributesCache.set('ol-groupSSOActive', true) @@ -286,6 +294,7 @@ describe('ManagedUserDropdownButton', function () { Cypress.dom.isVisible($el) }) }) + it('should make the correct post request when resend SSO invite is clicked ', function () { cy.window().then(win => { win.metaAttributesCache.set('ol-groupSSOActive', true) diff --git a/services/web/test/unit/src/UserMembership/UserMembershipViewModelTests.js b/services/web/test/unit/src/UserMembership/UserMembershipViewModelTests.js index 07a3b2f237..7ea0c35855 100644 --- a/services/web/test/unit/src/UserMembership/UserMembershipViewModelTests.js +++ b/services/web/test/unit/src/UserMembership/UserMembershipViewModelTests.js @@ -42,6 +42,11 @@ describe('UserMembershipViewModel', function () { enrollment: { managedBy: 'mock-group-id', enrolledAt: new Date(), + sso: { + groupId: 'abc123abc123', + linkedAt: new Date(), + primary: true, + }, }, } }) diff --git a/services/web/types/group-management/user.ts b/services/web/types/group-management/user.ts index c4cb92c9e9..a436cd83a0 100644 --- a/services/web/types/group-management/user.ts +++ b/services/web/types/group-management/user.ts @@ -1,7 +1,13 @@ +export type SSOEnrollment = { + groupId: string + linkedAt: Date + primary: boolean +} + export type UserEnrollment = { managedBy?: string enrolledAt?: Date - sso?: object + sso?: SSOEnrollment[] } export type User = {