import { useEffect, useMemo, useState } from 'react'; import { OrgRole } from '@grafana/data'; import { selectors as e2eSelectors } from '@grafana/e2e-selectors'; import { config } from '@grafana/runtime'; import { Avatar, Box, Button, CellProps, Column, ConfirmModal, FetchDataFunc, Icon, InteractiveTable, Pagination, Stack, Tag, Text, Tooltip, } from '@grafana/ui'; import { UserRolePicker } from 'app/core/components/RolePicker/UserRolePicker'; import { fetchRoleOptions, updateUserRoles } from 'app/core/components/RolePicker/api'; import { RolePickerBadges } from 'app/core/components/RolePickerDrawer/RolePickerBadges'; import { TagBadge } from 'app/core/components/TagFilter/TagBadge'; import { contextSrv } from 'app/core/core'; import { Trans } from 'app/core/internationalization'; import { AccessControlAction, OrgUser, Role } from 'app/types'; import { OrgRolePicker } from '../OrgRolePicker'; type Cell = CellProps; const disabledRoleMessage = `This user's role is not editable because it is synchronized from your auth provider. Refer to the Grafana authentication docs for details.`; const getBasicRoleDisabled = (user: OrgUser) => { const isUserSynced = user?.isExternallySynced; return !contextSrv.hasPermissionInMetadata(AccessControlAction.OrgUsersWrite, user) || isUserSynced; }; const selectors = e2eSelectors.pages.UserListPage.UsersListPage; export interface Props { users: OrgUser[]; orgId?: number; onRoleChange: (role: OrgRole, user: OrgUser) => void; onRemoveUser: (user: OrgUser) => void; fetchData?: FetchDataFunc; changePage: (page: number) => void; page: number; totalPages: number; rolesLoading?: boolean; onUserRolesChange?: () => void; } export const OrgUsersTable = ({ users, orgId, onRoleChange, onUserRolesChange, onRemoveUser, fetchData, changePage, page, totalPages, rolesLoading, }: Props) => { const [userToRemove, setUserToRemove] = useState(null); const [roleOptions, setRoleOptions] = useState([]); useEffect(() => { async function fetchOptions() { try { if (contextSrv.hasPermission(AccessControlAction.ActionRolesList)) { let options = await fetchRoleOptions(orgId); setRoleOptions(options); } } catch (e) { console.error('Error loading options'); } } if (contextSrv.licensedAccessControlEnabled()) { fetchOptions(); } }, [orgId]); const columns: Array> = useMemo( () => [ { id: 'avatarUrl', header: '', cell: ({ cell: { value } }: Cell<'avatarUrl'>) => value && , }, { id: 'login', header: 'Login', cell: ({ cell: { value } }: Cell<'login'>) =>
{value}
, sortType: 'string', }, { id: 'email', header: 'Email', cell: ({ cell: { value } }: Cell<'email'>) => value, sortType: 'string', }, { id: 'name', header: 'Name', cell: ({ cell: { value } }: Cell<'name'>) => value, sortType: 'string', }, { id: 'lastSeenAtAge', header: 'Last active', cell: ({ cell: { value } }: Cell<'lastSeenAtAge'>) => { return ( <> {value && ( <> {value === '10 years' ? ( Never ) : ( value )} )} ); }, sortType: (a, b) => new Date(a.original.lastSeenAt).getTime() - new Date(b.original.lastSeenAt).getTime(), }, { id: 'role', header: 'Role', cell: ({ cell: { value }, row: { original } }: Cell<'role'>) => { const basicRoleDisabled = getBasicRoleDisabled(original); const onUserRolesUpdate = async (newRoles: Role[], userId: number, orgId: number | undefined) => { await updateUserRoles(newRoles, userId, orgId); if (onUserRolesChange) { onUserRolesChange(); } }; if (config.featureToggles.rolePickerDrawer) { return ; } return contextSrv.licensedAccessControlEnabled() ? ( onRoleChange(newRole, original)} basicRoleDisabled={basicRoleDisabled} basicRoleDisabledMessage={disabledRoleMessage} width={40} /> ) : ( onRoleChange(newRole, original)} /> ); }, }, { id: 'info', header: '', cell: ({ row: { original } }: Cell) => { const basicRoleDisabled = getBasicRoleDisabled(original); return ( basicRoleDisabled && ( This user's role is not editable because it is synchronized from your auth provider. Refer to the  Grafana authentication docs  for details. } > ) ); }, }, { id: 'authLabels', header: 'Origin', cell: ({ cell: { value } }: Cell<'authLabels'>) => ( <>{Array.isArray(value) && value.length > 0 && } ), }, { id: 'isDisabled', header: '', cell: ({ cell: { value } }: Cell<'isDisabled'>) => <>{value && }, }, { id: 'delete', header: '', cell: ({ row: { original } }: Cell) => { return ( contextSrv.hasPermissionInMetadata(AccessControlAction.OrgUsersRemove, original) && (