Skip to content

Commit

Permalink
fix: no team leads (#10145)
Browse files Browse the repository at this point in the history
Signed-off-by: Matt Krick <[email protected]>
  • Loading branch information
mattkrick authored Aug 21, 2024
1 parent 4a7df48 commit a1599e9
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 12 deletions.
2 changes: 1 addition & 1 deletion packages/client/hooks/useMeetingMemberAvatars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const useMeetingMemberAvatars = (meetingRef: useMeetingMemberAvatars_meeting$key
return meetingMembers
.map(({user}) => user)
.filter((user) => {
return user.lastSeenAtURLs?.includes(`/meet/${meetingId}`) && user.isConnected
return user?.lastSeenAtURLs?.includes(`/meet/${meetingId}`) && user?.isConnected
})
.sort((a, b) => (a.id === viewerId ? -1 : a.lastSeenAt < b.lastSeenAt ? -1 : 1))
}, [meetingMembers])
Expand Down
29 changes: 21 additions & 8 deletions packages/server/graphql/mutations/helpers/removeTeamMember.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,27 @@ const removeTeamMember = async (
// see if they were a leader, make a new guy leader so later we can reassign tasks
const activeTeamMembers = await dataLoader.get('teamMembersByTeamId').load(teamId)
const teamMember = activeTeamMembers.find((t) => t.id === teamMemberId)
const {isLead, isNotRemoved} = teamMember ?? {}
// if the guy being removed is the leader & not the last, pick a new one. else, use him
const teamLeader = activeTeamMembers.find((t) => t.isLead === !isLead) || teamMember
if (!isNotRemoved || !teamMember || !teamLeader) {
throw new Error('Team member already removed')
if (!teamMember) {
return {
user: undefined,
notificationId: undefined,
archivedTaskIds: [] as string[],
reassignedTaskIds: [] as string[]
}
}
const currentTeamLeader = activeTeamMembers.find((t) => t.isLead)!
if (!currentTeamLeader) {
throw new Error('Team lead does not exist')
}

const {isLead} = teamMember
const willArchive = activeTeamMembers.length === 1
const nextTeamLead =
isLead && !willArchive
? activeTeamMembers.find((teamMember) => teamMember.id !== teamMemberId)!
: currentTeamLeader

if (activeTeamMembers.length === 1) {
if (willArchive) {
await Promise.all([
// archive single-person teams
pg.updateTable('Team').set({isArchived: true}).where('id', '=', teamId).execute(),
Expand All @@ -51,7 +64,7 @@ const removeTeamMember = async (
await pg
.updateTable('TeamMember')
.set(({not}) => ({isLead: not('isLead')}))
.where('id', 'in', [teamMemberId, teamLeader.id])
.where('id', 'in', [teamMemberId, nextTeamLead.id])
.execute()
}

Expand Down Expand Up @@ -82,7 +95,7 @@ const removeTeamMember = async (
)
.update(
{
userId: teamLeader.userId
userId: nextTeamLead.userId
},
{returnChanges: true}
)('changes')('new_val')
Expand Down
5 changes: 4 additions & 1 deletion packages/server/graphql/mutations/promoteToTeamLead.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ export default {
dataLoader.get('teamMembersByTeamId').load(teamId),
dataLoader.get('teams').loadNonNull(teamId)
])
const oldLead = teamMembers.find(({isLead}) => isLead)!
const oldLead = teamMembers.find(({isLead}) => isLead)
if (!oldLead) {
return standardError(new Error('Team has no team lead'), {userId: viewerId})
}
const {id: oldLeadTeamMemberId} = oldLead
if (!isSuperUser(authToken)) {
const isOrgAdmin = await isUserOrgAdmin(viewerId, team.orgId, dataLoader)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ const acceptRequestToJoinDomain: MutationResolvers['acceptRequestToJoinDomain']
email,
openDrawer: 'manageTeam'
})
.onConflict((oc) => oc.column('id').doUpdateSet({isNotRemoved: true}))
.onConflict((oc) => oc.column('id').doUpdateSet({isNotRemoved: true, isLead: false}))
.execute()
])

Expand Down
47 changes: 47 additions & 0 deletions packages/server/postgres/migrations/1724174924811_oneTeamLead.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {Kysely, PostgresDialect, sql} from 'kysely'
import connectRethinkDB from '../../database/connectRethinkDB'
import getPg from '../getPg'

export async function up() {
await connectRethinkDB()
const pg = new Kysely<any>({
dialect: new PostgresDialect({
pool: getPg()
})
})
const teamsWithout1Leader = await pg
.selectFrom('TeamMember')
.select('teamId')
.select(({fn}) => fn.count('id').as('count'))
.where('isNotRemoved', '=', true)
.groupBy('teamId')
.having(sql<boolean>`SUM(CASE WHEN "isLead" = true THEN 1 ELSE 0 END) != 1`)
.execute()

await Promise.all(
teamsWithout1Leader.map(async (row) => {
const {teamId} = row
// remove all leads for the cases where we had more than 1
await pg.updateTable('TeamMember').set({isLead: false}).where('teamId', '=', teamId).execute()
await pg
.with('NextLead', (qb) =>
qb
.selectFrom('TeamMember')
.select('id')
.where('teamId', '=', teamId)
.where('isNotRemoved', '=', true)
.orderBy('createdAt', 'asc')
.limit(1)
)
.updateTable('TeamMember')
.set({isLead: true})
.where(({eb, selectFrom}) => eb('id', '=', selectFrom('NextLead').select('id')))
.returning('id')
.execute()
})
)
}

export async function down() {
// noop
}
2 changes: 1 addition & 1 deletion packages/server/safeMutations/acceptTeamInvitation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const acceptTeamInvitation = async (team: Team, userId: string, dataLoader: Data
email,
openDrawer: 'manageTeam'
})
.onConflict((oc) => oc.column('id').doUpdateSet({isNotRemoved: true}))
.onConflict((oc) => oc.column('id').doUpdateSet({isNotRemoved: true, isLead: false}))
.execute(),
r
.table('TeamInvitation')
Expand Down

0 comments on commit a1599e9

Please sign in to comment.