import { useCallback, useMemo } from 'react' import { Link, useLocation, useParams, useSearchParams } from 'react-router-dom' import { Form, Formik } from 'formik' import { UserAccessPermission } from '@prisma/client' import classNames from 'classnames' import { trpc, inferQueryOutput } from '~/utils/trpc' import IVButton from '~/components/IVButton' import IVAvatar from '~/components/IVAvatar' import { userAccessPermissionToString } from '~/utils/text' import { notify } from '~/components/NotificationCenter' import useDashboard, { useHasPermission } from '~/components/DashboardContext' import { getPrimaryRole } from '~/utils/permissions' import IconChevronDown from '~/icons/compiled/ChevronDown' import IconChevronRight from '~/icons/compiled/ChevronRight' import IVDialog, { useDialogState } from '~/components/IVDialog' import PermissionSelector from '~/components/PermissionSelector' import IVTooltip from '~/components/IVTooltip' import KeysList from '~/components/KeysList' export default function UsersList({ data, onChange, }: { data: inferQueryOutput<'dashboard.users.index'> onChange?: () => void }) { const [searchParams] = useSearchParams() const location = useLocation() const { users, keys } = data ?? { users: [], keys: [] } const userKeyMap = useMemo( () => keys.reduce((map, key) => { let arr = map.get(key.userId) if (!arr) { arr = [] map.set(key.userId, arr) } arr.push(key) return map }, new Map()) ?? new Map(), [keys] ) if (!data) return null const selectedUserId = searchParams.get('userId') return (
) } type UserAccess = inferQueryOutput<'dashboard.users.index'>['users'][0] function getCurrentGroup(userAccess: UserAccess, groupId?: string) { if (!groupId) return null const group = userAccess.groupMemberships.find( gm => gm.group.id === groupId )?.group return group || null } function ExpandedUser({ userAccess, keys, onChange, }: { userAccess: UserAccess keys: inferQueryOutput<'dashboard.users.index'>['keys'] onChange?: () => void }) { const { groupId } = useParams<{ groupId: string | undefined }>() const { me, organization } = useDashboard() const editUserAccess = trpc.useMutation('organization.edit-user-access') const canWriteUsers = useHasPermission('WRITE_USERS') const canViewUserKeys = useHasPermission('READ_ORG_USER_API_KEY_EXISTENCE') const ctx = trpc.useContext() const removeUserDialog = useDialogState() const removeUserMutation = trpc.useMutation('organization.remove-user') const removeUserMembershipDialog = useDialogState() const removeUserMembershipMutation = trpc.useMutation('group.users.remove') const isUserExternallyManaged = userAccess.user.idpId && organization.sso?.workosOrganizationId // Don't allow editing your own or the owner's permissions const canEditPermissions = userAccess.user.id !== me.id && userAccess.user.id !== organization.ownerId const group = getCurrentGroup(userAccess, groupId) const canRemoveUserFromOrg = canWriteUsers && !isUserExternallyManaged const canRemoveUserFromGroup = canWriteUsers && !group?.scimGroupId const role = getPrimaryRole(userAccess.permissions) ?? 'ADMIN' const onRemoveUser = useCallback( (event: React.FormEvent) => { event.preventDefault() removeUserMutation.mutate( { id: userAccess.id }, { onSuccess() { notify.success( `${userAccess.user.email} was removed from the organization.` ) if (onChange) { onChange() } }, } ) }, [onChange, removeUserMutation, userAccess] ) const onRemoveUserMembership = useCallback( (event: React.FormEvent) => { event.preventDefault() if (!groupId) return removeUserMembershipMutation.mutate( { groupId, userOrganizationAccessId: userAccess.id, }, { onSuccess() { notify.success( `${userAccess.user.email} was removed from the team.` ) if (onChange) { onChange() } }, } ) }, [onChange, removeUserMembershipMutation, groupId, userAccess] ) return (
{canWriteUsers && (

Organization access

initialValues={{ role, }} onSubmit={async ({ role }) => { if (!canEditPermissions || editUserAccess.isLoading) return editUserAccess.mutate( { id: userAccess.id, data: { permissions: [role], }, }, { onSuccess() { notify.success('User role has been updated.') if (onChange) { onChange() } }, } ) }} >
{canEditPermissions && ( )}
)} {keys.length > 0 && canViewUserKeys && (

API Keys

ctx.refetchQueries(['dashboard.users.index'])} />
)}
{canRemoveUserFromOrg && ( )} {canRemoveUserFromGroup && groupId && ( )}

Are you sure you want to remove this user from the organization?

All API keys belonging to this user will also be disabled.

Are you sure you want to remove this user from the team?

) }