import { useMemo } from 'react'; import Skeleton from 'react-loading-skeleton'; import { Trans, t } from '@grafana/i18n'; import { Avatar, CellProps, Column, InteractiveTable, Pagination, Stack, TextLink, Button, IconButton, Icon, } from '@grafana/ui'; import { UserRolePicker } from 'app/core/components/RolePicker/UserRolePicker'; import { contextSrv } from 'app/core/core'; import { AccessControlAction, OrgRole, Role, ServiceAccountDTO } from 'app/types'; import { OrgRolePicker } from '../admin/OrgRolePicker'; type Cell = CellProps< ServiceAccountDTO, ServiceAccountDTO[T] >; interface ServiceAccountTableProps { services: ServiceAccountDTO[]; onRoleChange: (role: OrgRole, serviceAccount: ServiceAccountDTO) => void; roleOptions: Role[]; onRemoveButtonClick: (serviceAccount: ServiceAccountDTO) => void; onDisable: (serviceAccount: ServiceAccountDTO) => void; onEnable: (serviceAccount: ServiceAccountDTO) => void; onAddTokenClick: (serviceAccount: ServiceAccountDTO) => void; showPaging?: boolean; totalPages: number; onChangePage: (page: number) => void; currentPage: number; isLoading: boolean; } export const ServiceAccountTable = ({ services, onRoleChange, roleOptions, onRemoveButtonClick, onDisable, onEnable, onAddTokenClick, showPaging, totalPages, onChangePage, currentPage, isLoading, }: ServiceAccountTableProps) => { const columns: Array> = useMemo( () => [ { id: 'avatarUrl', header: '', cell: ({ cell: { value }, row: { original } }: Cell<'role'>) => { return getCellContent(value, original, isLoading, 'avatarUrl'); }, }, { id: 'name', header: 'Account', cell: ({ cell: { value }, row: { original } }: Cell<'role'>) => { return getCellContent(value, original, isLoading); }, sortType: 'string', }, { id: 'id', header: 'ID', cell: ({ cell: { value }, row: { original } }: Cell<'role'>) => { return getCellContent(value, original, isLoading, 'id'); }, }, { id: 'role', header: 'Roles', cell: ({ cell: { value }, row: { original } }: Cell<'role'>) => { return getRoleCell(value, original, isLoading, roleOptions, onRoleChange); }, }, { id: 'tokens', header: 'Tokens', cell: ({ cell: { value }, row: { original } }: Cell<'role'>) => { return getCellContent(value, original, isLoading, 'tokens'); }, }, { id: 'actions', header: '', cell: ({ row: { original } }: Cell) => { return getActionsCell(original, isLoading, onAddTokenClick, onEnable, onDisable, onRemoveButtonClick); }, }, ], [isLoading, onAddTokenClick, onDisable, onEnable, onRemoveButtonClick, onRoleChange, roleOptions] ); return ( String(service.id)} /> {showPaging && totalPages > 1 && ( )} ); }; const getCellContent = ( value: string, original: ServiceAccountDTO, isLoading: boolean, columnName?: Column['id'] ) => { if (isLoading) { return columnName === 'avatarUrl' ? : ; } const href = `/org/serviceaccounts/${original.uid}`; const ariaLabel = `Edit service account's ${original.name} details`; switch (columnName) { case 'avatarUrl': return ( ); case 'id': return ( {original.login} ); case 'tokens': return ( {value || 'No tokens'} ); default: return ( {value} ); } }; const getRoleCell = ( value: OrgRole, original: ServiceAccountDTO, isLoading: boolean, roleOptions: Role[], onRoleChange: (role: OrgRole, serviceAccount: ServiceAccountDTO) => void ) => { const displayRolePicker = contextSrv.hasPermission(AccessControlAction.ActionRolesList) && contextSrv.hasPermission(AccessControlAction.ActionUserRolesList); const canUpdateRole = contextSrv.hasPermissionInMetadata(AccessControlAction.ServiceAccountsWrite, original); if (isLoading) { return ; } else { return contextSrv.licensedAccessControlEnabled() ? ( displayRolePicker && ( onRoleChange(newRole, original)} roleOptions={roleOptions} basicRoleDisabled={!canUpdateRole} disabled={original.isExternal || original.isDisabled} width={40} /> ) ) : ( onRoleChange(newRole, original)} /> ); } }; const getActionsCell = ( original: ServiceAccountDTO, isLoading: boolean, onAddTokenClick: (serviceAccount: ServiceAccountDTO) => void, onEnable: (serviceAccount: ServiceAccountDTO) => void, onDisable: (serviceAccount: ServiceAccountDTO) => void, onRemoveButtonClick: (serviceAccount: ServiceAccountDTO) => void ) => { if (isLoading) { return ; } else { return !original.isExternal ? ( {contextSrv.hasPermission(AccessControlAction.ServiceAccountsWrite) && !original.tokens && ( )} {contextSrv.hasPermissionInMetadata(AccessControlAction.ServiceAccountsWrite, original) && (original.isDisabled ? ( ) : ( ))} {contextSrv.hasPermissionInMetadata(AccessControlAction.ServiceAccountsDelete, original) && ( onRemoveButtonClick(original)} /> )} ) : ( ); } }; ServiceAccountTable.displayName = 'ServiceAccountTable';