mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-29 07:53:42 -05:00
Merge pull request #15669 from overleaf/ab-fix-sso-linking-status
[web] Fix SSO status in group members table GitOrigin-RevId: e54e7b0c9640f0b96d9692c0208357e3bac2de91
This commit is contained in:
parent
1819f3e4e7
commit
c4bea21ee2
7 changed files with 92 additions and 35 deletions
|
@ -66,6 +66,7 @@ function buildUserViewModel(user, isInvite) {
|
||||||
? {
|
? {
|
||||||
managedBy: user.enrollment.managedBy,
|
managedBy: user.enrollment.managedBy,
|
||||||
enrolledAt: user.enrollment.enrolledAt,
|
enrolledAt: user.enrollment.enrolledAt,
|
||||||
|
sso: user.enrollment.sso,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,27 @@
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import getMeta from '@/utils/meta'
|
||||||
import { User } from '../../../../../../types/group-management/user'
|
import { User } from '../../../../../../types/group-management/user'
|
||||||
import MaterialIcon from '@/shared/components/material-icon'
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
|
|
||||||
type SSOStatusProps = {
|
type SSOStatusProps = {
|
||||||
user: User
|
user: User
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SSOStatus({ user }: SSOStatusProps) {
|
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 { t } = useTranslation()
|
||||||
const invitedSSO = (
|
return (
|
||||||
<span className="security-state-invite-pending">
|
<span className="security-state-invite-pending">
|
||||||
<MaterialIcon
|
<MaterialIcon
|
||||||
type="schedule"
|
type="schedule"
|
||||||
|
@ -17,22 +31,24 @@ export default function SSOStatus({ user }: SSOStatusProps) {
|
||||||
{t('sso')}
|
{t('sso')}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
const acceptedSSO = (
|
}
|
||||||
|
|
||||||
|
function SSOLinked() {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
return (
|
||||||
<span className="security-state-managed">
|
<span className="security-state-managed">
|
||||||
<MaterialIcon type="check" accessibilityLabel={t('sso_active')} />
|
<MaterialIcon type="check" accessibilityLabel={t('sso_active')} />
|
||||||
{t('sso')}
|
{t('sso')}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
const notAcceptedSSO = (
|
}
|
||||||
|
|
||||||
|
function SSOUnlinked() {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
return (
|
||||||
<span className="security-state-not-managed">
|
<span className="security-state-not-managed">
|
||||||
<MaterialIcon type="close" accessibilityLabel={t('sso_not_active')} />
|
<MaterialIcon type="close" accessibilityLabel={t('sso_not_active')} />
|
||||||
{t('sso')}
|
{t('sso')}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
|
|
||||||
if (user.invite) {
|
|
||||||
return invitedSSO
|
|
||||||
}
|
|
||||||
|
|
||||||
return user.enrollment?.sso ? acceptedSSO : notAcceptedSSO
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import GroupMembers from '@/features/group-management/components/group-members'
|
import GroupMembers from '@/features/group-management/components/group-members'
|
||||||
import { GroupMembersProvider } from '@/features/group-management/context/group-members-context'
|
import { GroupMembersProvider } from '@/features/group-management/context/group-members-context'
|
||||||
|
import { User } from '../../../../../types/group-management/user'
|
||||||
|
|
||||||
const GROUP_ID = '777fff777fff'
|
const GROUP_ID = '777fff777fff'
|
||||||
const PATHS = {
|
const PATHS = {
|
||||||
|
@ -173,7 +174,7 @@ describe('GroupMembers', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('with Managed Users enabled', function () {
|
describe('with Managed Users enabled', function () {
|
||||||
const JOHN_DOE = {
|
const JOHN_DOE: User = {
|
||||||
_id: 'abc123def456',
|
_id: 'abc123def456',
|
||||||
first_name: 'John',
|
first_name: 'John',
|
||||||
last_name: 'Doe',
|
last_name: 'Doe',
|
||||||
|
@ -181,7 +182,7 @@ describe('GroupMembers', function () {
|
||||||
last_active_at: new Date('2023-01-15'),
|
last_active_at: new Date('2023-01-15'),
|
||||||
invite: true,
|
invite: true,
|
||||||
}
|
}
|
||||||
const BOBBY_LAPOINTE = {
|
const BOBBY_LAPOINTE: User = {
|
||||||
_id: 'bcd234efa567',
|
_id: 'bcd234efa567',
|
||||||
first_name: 'Bobby',
|
first_name: 'Bobby',
|
||||||
last_name: 'Lapointe',
|
last_name: 'Lapointe',
|
||||||
|
@ -189,7 +190,7 @@ describe('GroupMembers', function () {
|
||||||
last_active_at: new Date('2023-01-02'),
|
last_active_at: new Date('2023-01-02'),
|
||||||
invite: false,
|
invite: false,
|
||||||
}
|
}
|
||||||
const CLAIRE_JENNINGS = {
|
const CLAIRE_JENNINGS: User = {
|
||||||
_id: 'defabc231453',
|
_id: 'defabc231453',
|
||||||
first_name: 'Claire',
|
first_name: 'Claire',
|
||||||
last_name: 'Jennings',
|
last_name: 'Jennings',
|
||||||
|
@ -199,10 +200,13 @@ describe('GroupMembers', function () {
|
||||||
enrollment: {
|
enrollment: {
|
||||||
managedBy: GROUP_ID,
|
managedBy: GROUP_ID,
|
||||||
enrolledAt: new Date('2023-01-03'),
|
enrolledAt: new Date('2023-01-03'),
|
||||||
sso: {
|
sso: [
|
||||||
providerId: '123',
|
{
|
||||||
externalId: '123',
|
groupId: GROUP_ID,
|
||||||
|
linkedAt: new Date(),
|
||||||
|
primary: true,
|
||||||
},
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,7 +380,7 @@ describe('GroupMembers', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('with Group SSO enabled', function () {
|
describe('with Group SSO enabled', function () {
|
||||||
const JOHN_DOE = {
|
const JOHN_DOE: User = {
|
||||||
_id: 'abc123def456',
|
_id: 'abc123def456',
|
||||||
first_name: 'John',
|
first_name: 'John',
|
||||||
last_name: 'Doe',
|
last_name: 'Doe',
|
||||||
|
@ -384,7 +388,7 @@ describe('GroupMembers', function () {
|
||||||
last_active_at: new Date('2023-01-15'),
|
last_active_at: new Date('2023-01-15'),
|
||||||
invite: true,
|
invite: true,
|
||||||
}
|
}
|
||||||
const BOBBY_LAPOINTE = {
|
const BOBBY_LAPOINTE: User = {
|
||||||
_id: 'bcd234efa567',
|
_id: 'bcd234efa567',
|
||||||
first_name: 'Bobby',
|
first_name: 'Bobby',
|
||||||
last_name: 'Lapointe',
|
last_name: 'Lapointe',
|
||||||
|
@ -392,7 +396,7 @@ describe('GroupMembers', function () {
|
||||||
last_active_at: new Date('2023-01-02'),
|
last_active_at: new Date('2023-01-02'),
|
||||||
invite: false,
|
invite: false,
|
||||||
}
|
}
|
||||||
const CLAIRE_JENNINGS = {
|
const CLAIRE_JENNINGS: User = {
|
||||||
_id: 'defabc231453',
|
_id: 'defabc231453',
|
||||||
first_name: 'Claire',
|
first_name: 'Claire',
|
||||||
last_name: 'Jennings',
|
last_name: 'Jennings',
|
||||||
|
@ -402,10 +406,13 @@ describe('GroupMembers', function () {
|
||||||
enrollment: {
|
enrollment: {
|
||||||
managedBy: GROUP_ID,
|
managedBy: GROUP_ID,
|
||||||
enrolledAt: new Date('2023-01-03'),
|
enrolledAt: new Date('2023-01-03'),
|
||||||
sso: {
|
sso: [
|
||||||
providerId: '123',
|
{
|
||||||
externalId: '123',
|
groupId: GROUP_ID,
|
||||||
|
linkedAt: new Date(),
|
||||||
|
primary: true,
|
||||||
},
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import GroupMembers from '@/features/group-management/components/group-members'
|
import GroupMembers from '@/features/group-management/components/group-members'
|
||||||
import { GroupMembersProvider } from '@/features/group-management/context/group-members-context'
|
import { GroupMembersProvider } from '@/features/group-management/context/group-members-context'
|
||||||
|
import { User } from '../../../../../types/group-management/user'
|
||||||
|
|
||||||
const GROUP_ID = '777fff777fff'
|
const GROUP_ID = '777fff777fff'
|
||||||
const JOHN_DOE = {
|
const JOHN_DOE: User = {
|
||||||
_id: 'abc123def456',
|
_id: 'abc123def456',
|
||||||
first_name: 'John',
|
first_name: 'John',
|
||||||
last_name: 'Doe',
|
last_name: 'Doe',
|
||||||
|
@ -10,15 +11,24 @@ const JOHN_DOE = {
|
||||||
last_active_at: new Date('2023-01-15'),
|
last_active_at: new Date('2023-01-15'),
|
||||||
invite: true,
|
invite: true,
|
||||||
}
|
}
|
||||||
const BOBBY_LAPOINTE = {
|
const BOBBY_LAPOINTE: User = {
|
||||||
_id: 'bcd234efa567',
|
_id: 'bcd234efa567',
|
||||||
first_name: 'Bobby',
|
first_name: 'Bobby',
|
||||||
last_name: 'Lapointe',
|
last_name: 'Lapointe',
|
||||||
email: 'bobby.lapointe@test.com',
|
email: 'bobby.lapointe@test.com',
|
||||||
last_active_at: new Date('2023-01-02'),
|
last_active_at: new Date('2023-01-02'),
|
||||||
invite: false,
|
invite: false,
|
||||||
|
enrollment: {
|
||||||
|
sso: [
|
||||||
|
{
|
||||||
|
groupId: 'another',
|
||||||
|
linkedAt: new Date(),
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
const CLAIRE_JENNINGS = {
|
const CLAIRE_JENNINGS: User = {
|
||||||
_id: 'defabc231453',
|
_id: 'defabc231453',
|
||||||
first_name: 'Claire',
|
first_name: 'Claire',
|
||||||
last_name: 'Jennings',
|
last_name: 'Jennings',
|
||||||
|
@ -28,10 +38,13 @@ const CLAIRE_JENNINGS = {
|
||||||
enrollment: {
|
enrollment: {
|
||||||
managedBy: GROUP_ID,
|
managedBy: GROUP_ID,
|
||||||
enrolledAt: new Date('2023-01-03'),
|
enrolledAt: new Date('2023-01-03'),
|
||||||
sso: {
|
sso: [
|
||||||
providerId: '123',
|
{
|
||||||
externalId: '123',
|
groupId: GROUP_ID,
|
||||||
|
linkedAt: new Date(),
|
||||||
|
primary: true,
|
||||||
},
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
const PATHS = {
|
const PATHS = {
|
||||||
|
|
|
@ -233,6 +233,7 @@ describe('ManagedUserDropdownButton', function () {
|
||||||
},
|
},
|
||||||
isEntityAdmin: undefined,
|
isEntityAdmin: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
cy.window().then(win => {
|
cy.window().then(win => {
|
||||||
win.metaAttributesCache.set('ol-users', [user])
|
win.metaAttributesCache.set('ol-users', [user])
|
||||||
|
@ -241,11 +242,13 @@ describe('ManagedUserDropdownButton', function () {
|
||||||
win.metaAttributesCache.set('ol-groupSSOActive', true)
|
win.metaAttributesCache.set('ol-groupSSOActive', true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should show resend invite when user is admin', function () {
|
it('should show resend invite when user is admin', function () {
|
||||||
mountDropDownComponent({ ...user, isEntityAdmin: true }, '123abc')
|
mountDropDownComponent({ ...user, isEntityAdmin: true }, '123abc')
|
||||||
cy.get('.action-btn').click()
|
cy.get('.action-btn').click()
|
||||||
cy.findByTestId('resend-sso-link-invite-action').should('exist')
|
cy.findByTestId('resend-sso-link-invite-action').should('exist')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not show resend invite when SSO is disabled', function () {
|
it('should not show resend invite when SSO is disabled', function () {
|
||||||
cy.window().then(win => {
|
cy.window().then(win => {
|
||||||
win.metaAttributesCache.set('ol-groupSSOActive', false)
|
win.metaAttributesCache.set('ol-groupSSOActive', false)
|
||||||
|
@ -254,6 +257,7 @@ describe('ManagedUserDropdownButton', function () {
|
||||||
cy.get('.action-btn').click()
|
cy.get('.action-btn').click()
|
||||||
cy.findByTestId('resend-sso-link-invite-action').should('not.exist')
|
cy.findByTestId('resend-sso-link-invite-action').should('not.exist')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not show resend invite when user has accepted SSO already', function () {
|
it('should not show resend invite when user has accepted SSO already', function () {
|
||||||
cy.window().then(win => {
|
cy.window().then(win => {
|
||||||
win.metaAttributesCache.set('ol-groupSSOActive', false)
|
win.metaAttributesCache.set('ol-groupSSOActive', false)
|
||||||
|
@ -264,10 +268,13 @@ describe('ManagedUserDropdownButton', function () {
|
||||||
enrollment: {
|
enrollment: {
|
||||||
managedBy: 'some-group',
|
managedBy: 'some-group',
|
||||||
enrolledAt: new Date(),
|
enrolledAt: new Date(),
|
||||||
sso: {
|
sso: [
|
||||||
providerId: '123',
|
{
|
||||||
externalId: '123',
|
groupId: 'abc123abc123',
|
||||||
|
linkedAt: new Date(),
|
||||||
|
primary: true,
|
||||||
},
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'123abc'
|
'123abc'
|
||||||
|
@ -275,6 +282,7 @@ describe('ManagedUserDropdownButton', function () {
|
||||||
cy.get('.action-btn').click()
|
cy.get('.action-btn').click()
|
||||||
cy.findByTestId('resend-sso-link-invite-action').should('not.exist')
|
cy.findByTestId('resend-sso-link-invite-action').should('not.exist')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should show the resend SSO invite option when dropdown button is clicked', function () {
|
it('should show the resend SSO invite option when dropdown button is clicked', function () {
|
||||||
cy.window().then(win => {
|
cy.window().then(win => {
|
||||||
win.metaAttributesCache.set('ol-groupSSOActive', true)
|
win.metaAttributesCache.set('ol-groupSSOActive', true)
|
||||||
|
@ -286,6 +294,7 @@ describe('ManagedUserDropdownButton', function () {
|
||||||
Cypress.dom.isVisible($el)
|
Cypress.dom.isVisible($el)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should make the correct post request when resend SSO invite is clicked ', function () {
|
it('should make the correct post request when resend SSO invite is clicked ', function () {
|
||||||
cy.window().then(win => {
|
cy.window().then(win => {
|
||||||
win.metaAttributesCache.set('ol-groupSSOActive', true)
|
win.metaAttributesCache.set('ol-groupSSOActive', true)
|
||||||
|
|
|
@ -42,6 +42,11 @@ describe('UserMembershipViewModel', function () {
|
||||||
enrollment: {
|
enrollment: {
|
||||||
managedBy: 'mock-group-id',
|
managedBy: 'mock-group-id',
|
||||||
enrolledAt: new Date(),
|
enrolledAt: new Date(),
|
||||||
|
sso: {
|
||||||
|
groupId: 'abc123abc123',
|
||||||
|
linkedAt: new Date(),
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
|
export type SSOEnrollment = {
|
||||||
|
groupId: string
|
||||||
|
linkedAt: Date
|
||||||
|
primary: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export type UserEnrollment = {
|
export type UserEnrollment = {
|
||||||
managedBy?: string
|
managedBy?: string
|
||||||
enrolledAt?: Date
|
enrolledAt?: Date
|
||||||
sso?: object
|
sso?: SSOEnrollment[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type User = {
|
export type User = {
|
||||||
|
|
Loading…
Reference in a new issue