Skip to content

Commit e6eda13

Browse files
committed
fix: Org admin can remove team members without being on team
The mutation tried to always load the viewer team member which would fail if the org admin wasn't on the team.
1 parent 025c44e commit e6eda13

File tree

6 files changed

+33
-48
lines changed

6 files changed

+33
-48
lines changed

Diff for: packages/client/components/DashboardAvatars/TeamMemberAvatarMenu.tsx

+4-8
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,14 @@ const TeamMemberAvatarMenu = (props: Props) => {
3838
graphql`
3939
fragment TeamMemberAvatarMenu_teamMember on TeamMember {
4040
isSelf
41-
user {
42-
id
43-
preferredName
44-
}
41+
userId
4542
isLead
4643
}
4744
`,
4845
teamMemberRef
4946
)
5047
const atmosphere = useAtmosphere()
51-
const {user} = teamMember
52-
const {id: userId, preferredName} = user
48+
const {userId} = teamMember
5349
const {viewerId} = atmosphere
5450
const isSelf = userId === viewerId
5551
const isViewerTeamAdmin = isViewerLead || isViewerOrgAdmin
@@ -60,14 +56,14 @@ const TeamMemberAvatarMenu = (props: Props) => {
6056
<MenuItem
6157
key='promote'
6258
onClick={togglePromote}
63-
label={<StyledLabel>Promote {preferredName} to Team Lead</StyledLabel>}
59+
label={<StyledLabel>Promote to Team Lead</StyledLabel>}
6460
/>
6561
)}
6662
{isViewerTeamAdmin && !isSelf && (
6763
<MenuItem
6864
key='remove'
6965
onClick={toggleRemove}
70-
label={<StyledLabel>Remove {preferredName} from Team</StyledLabel>}
66+
label={<StyledLabel>Remove from Team</StyledLabel>}
7167
/>
7268
)}
7369
{!isViewerLead && isSelf && (

Diff for: packages/client/components/MenuItem.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ interface Props {
2424
const MenuItemStyles = styled('div')<{isActive: boolean; isDisabled: boolean | undefined}>(
2525
({isActive, isDisabled}) => ({
2626
alignItems: 'center',
27+
//overflowWrap: 'break-word',
2728
backgroundColor: isActive ? PALETTE.SLATE_200 : undefined,
2829
color: isDisabled ? PALETTE.SLATE_600 : PALETTE.SLATE_700,
2930
cursor: isDisabled ? 'not-allowed' : 'pointer',

Diff for: packages/client/modules/teamDashboard/components/PromoteTeamMemberModal/PromoteTeamMemberModal.tsx

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import styled from '@emotion/styled'
21
import graphql from 'babel-plugin-relay/macro'
32
import {useFragment} from 'react-relay'
43
import useAtmosphere from '~/hooks/useAtmosphere'
@@ -12,14 +11,6 @@ import useMutationProps from '../../../../hooks/useMutationProps'
1211
import PromoteToTeamLeadMutation from '../../../../mutations/PromoteToTeamLeadMutation'
1312
import {upperFirst} from '../../../../utils/upperFirst'
1413

15-
const StyledDialogContainer = styled(DialogContainer)({
16-
width: 420
17-
})
18-
19-
const StyledButton = styled(PrimaryButton)({
20-
margin: '1.5rem auto 0'
21-
})
22-
2314
interface Props {
2415
closePortal: () => void
2516
teamMember: PromoteTeamMemberModal_teamMember$key
@@ -70,15 +61,24 @@ const PromoteTeamMemberModal = (props: Props) => {
7061
const copy = `${copyStart} ${copyEnd}`
7162

7263
return (
73-
<StyledDialogContainer>
64+
<DialogContainer>
7465
<DialogTitle>{'Are you sure?'}</DialogTitle>
7566
<DialogContent>
7667
{copy}
77-
<StyledButton size='medium' onClick={handleClick} waiting={submitting}>
78-
<IconLabel icon='arrow_forward' iconAfter label={`Yes, promote ${preferredName}`} />
79-
</StyledButton>
68+
<PrimaryButton
69+
size='medium'
70+
className='mx-auto mt-6 mb-0'
71+
onClick={handleClick}
72+
waiting={submitting}
73+
>
74+
<IconLabel
75+
icon='arrow_forward'
76+
iconAfter
77+
label={<div className='break-word whitespace-normal'>Yes, promote {preferredName}</div>}
78+
/>
79+
</PrimaryButton>
8080
</DialogContent>
81-
</StyledDialogContainer>
81+
</DialogContainer>
8282
)
8383
}
8484

Diff for: packages/client/modules/teamDashboard/components/RemoveTeamMemberModal/RemoveTeamMemberModal.tsx

+9-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import styled from '@emotion/styled'
21
import graphql from 'babel-plugin-relay/macro'
32
import {useFragment} from 'react-relay'
43
import useAtmosphere from '~/hooks/useAtmosphere'
@@ -10,14 +9,6 @@ import IconLabel from '../../../../components/IconLabel'
109
import PrimaryButton from '../../../../components/PrimaryButton'
1110
import RemoveTeamMemberMutation from '../../../../mutations/RemoveTeamMemberMutation'
1211

13-
const StyledDialogContainer = styled(DialogContainer)({
14-
width: 320
15-
})
16-
17-
const StyledButton = styled(PrimaryButton)({
18-
margin: '1.5rem auto 0'
19-
})
20-
2112
interface Props {
2213
closePortal: () => void
2314
teamMember: RemoveTeamMemberModal_teamMember$key
@@ -44,16 +35,20 @@ const RemoveTeamMemberModal = (props: Props) => {
4435
RemoveTeamMemberMutation(atmosphere, {teamMemberId})
4536
}
4637
return (
47-
<StyledDialogContainer>
38+
<DialogContainer>
4839
<DialogTitle>Are you sure?</DialogTitle>
4940
<DialogContent>
5041
This will remove {preferredName} from the team.
5142
<br />
52-
<StyledButton size='medium' onClick={handleClick}>
53-
<IconLabel icon='arrow_forward' iconAfter label={`Remove ${preferredName}`} />
54-
</StyledButton>
43+
<PrimaryButton size='medium' className='mx-auto mt-6 mb-0' onClick={handleClick}>
44+
<IconLabel
45+
icon='arrow_forward'
46+
iconAfter
47+
label={<div className='break-word whitespace-normal'>Remove {preferredName}</div>}
48+
/>
49+
</PrimaryButton>
5550
</DialogContent>
56-
</StyledDialogContainer>
51+
</DialogContainer>
5752
)
5853
}
5954

Diff for: packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMemberMenu.tsx

+4-11
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,14 @@ export const OrgTeamMemberMenu = (props: OrgTeamMemberMenuProps) => {
3737
graphql`
3838
fragment OrgTeamMemberMenu_teamMember on TeamMember {
3939
isSelf
40-
user {
41-
id
42-
preferredName
43-
}
40+
userId
4441
isLead
4542
}
4643
`,
4744
teamMemberRef
4845
)
4946
const atmosphere = useAtmosphere()
50-
const {user} = teamMember
51-
const {id: userId, preferredName} = user
47+
const {userId} = teamMember
5248
const {viewerId} = atmosphere
5349
const isSelf = userId === viewerId
5450
const isViewerTeamAdmin = isViewerLead || isViewerOrgAdmin
@@ -57,16 +53,13 @@ export const OrgTeamMemberMenu = (props: OrgTeamMemberMenuProps) => {
5753
<Menu ariaLabel={'Select your action'} {...menuProps}>
5854
{isViewerTeamAdmin && (!isSelf || !isViewerLead) && (
5955
<MenuItem
60-
label={<StyledLabel>Promote {preferredName} to Team Lead</StyledLabel>}
56+
label={<StyledLabel>Promote to Team Lead</StyledLabel>}
6157
key='promote'
6258
onClick={togglePromote}
6359
/>
6460
)}
6561
{isViewerTeamAdmin && !isSelf && (
66-
<MenuItem
67-
label={<StyledLabel>Remove {preferredName} from Team</StyledLabel>}
68-
onClick={toggleRemove}
69-
/>
62+
<MenuItem label={<StyledLabel>Remove from Team</StyledLabel>} onClick={toggleRemove} />
7063
)}
7164
</Menu>
7265
)

Diff for: packages/server/graphql/mutations/removeTeamMember.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export default {
3434
const team = await dataLoader.get('teams').loadNonNull(teamId)
3535
const [isOrgAdmin, teamMember] = await Promise.all([
3636
isUserOrgAdmin(viewerId, team.orgId, dataLoader),
37-
dataLoader.get('teamMembers').loadNonNull(TeamMemberId.join(teamId, viewerId))
37+
dataLoader.get('teamMembers').load(TeamMemberId.join(teamId, viewerId))
3838
])
3939
const isViewerTeamLead = teamMember?.isLead
4040
const isSelf = viewerId === userId

0 commit comments

Comments
 (0)