Forráskód Böngészése

Merge pull request #15669 from overleaf/ab-fix-sso-linking-status

[web] Fix SSO status in group members table

GitOrigin-RevId: e54e7b0c9640f0b96d9692c0208357e3bac2de91
Alexandre Bourdin 2 éve
szülő
commit
c4bea21ee2

+ 1 - 0
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,
   }

+ 25 - 9
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 <PendingInvite />
+  }
+
+  const linkedSSO = user.enrollment?.sso?.some(sso => sso.groupId === groupId)
+
+  return linkedSSO ? <SSOLinked /> : <SSOUnlinked />
+}
+
+function PendingInvite() {
   const { t } = useTranslation()
-  const invitedSSO = (
+  return (
     <span className="security-state-invite-pending">
       <MaterialIcon
         type="schedule"
@@ -17,22 +31,24 @@ export default function SSOStatus({ user }: SSOStatusProps) {
       &nbsp; {t('sso')}
     </span>
   )
-  const acceptedSSO = (
+}
+
+function SSOLinked() {
+  const { t } = useTranslation()
+  return (
     <span className="security-state-managed">
       <MaterialIcon type="check" accessibilityLabel={t('sso_active')} />
       &nbsp; {t('sso')}
     </span>
   )
-  const notAcceptedSSO = (
+}
+
+function SSOUnlinked() {
+  const { t } = useTranslation()
+  return (
     <span className="security-state-not-managed">
       <MaterialIcon type="close" accessibilityLabel={t('sso_not_active')} />
       &nbsp; {t('sso')}
     </span>
   )
-
-  if (user.invite) {
-    return invitedSSO
-  }
-
-  return user.enrollment?.sso ? acceptedSSO : notAcceptedSSO
 }

+ 21 - 14
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,
+          },
+        ],
       },
     }
 

+ 20 - 7
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 = {

+ 13 - 4
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)

+ 5 - 0
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,
+        },
       },
     }
   })

+ 7 - 1
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 = {