import { css, cx } from '@emotion/css'; import { memo } from 'react'; import Skeleton from 'react-loading-skeleton'; import { GrafanaTheme2, OrgRole } from '@grafana/data'; import { Button, Icon, IconButton, Stack, useStyles2 } from '@grafana/ui'; import { SkeletonComponent, attachSkeleton } from '@grafana/ui/src/unstable'; import { UserRolePicker } from 'app/core/components/RolePicker/UserRolePicker'; import { contextSrv } from 'app/core/core'; import { OrgRolePicker } from 'app/features/admin/OrgRolePicker'; import { AccessControlAction, Role, ServiceAccountDTO } from 'app/types'; type ServiceAccountListItemProps = { serviceAccount: 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; }; const getServiceAccountsAriaLabel = (name: string) => { return `Edit service account's ${name} details`; }; const ServiceAccountListItemComponent = memo( ({ serviceAccount, onRoleChange, roleOptions, onRemoveButtonClick, onDisable, onEnable, onAddTokenClick, }: ServiceAccountListItemProps) => { const editUrl = `org/serviceaccounts/${serviceAccount.id}`; const styles = useStyles2(getStyles); const canUpdateRole = contextSrv.hasPermissionInMetadata(AccessControlAction.ServiceAccountsWrite, serviceAccount); const displayRolePicker = contextSrv.hasPermission(AccessControlAction.ActionRolesList) && contextSrv.hasPermission(AccessControlAction.ActionUserRolesList); return ( {`Avatar {serviceAccount.name} {serviceAccount.login} {contextSrv.licensedAccessControlEnabled() ? ( {displayRolePicker && ( onRoleChange(newRole, serviceAccount)} roleOptions={roleOptions} basicRoleDisabled={!canUpdateRole} disabled={serviceAccount.isExternal || serviceAccount.isDisabled} width={40} /> )} ) : ( onRoleChange(newRole, serviceAccount)} /> )}
{serviceAccount.tokens || 'No tokens'}
{!serviceAccount.isExternal && ( {contextSrv.hasPermission(AccessControlAction.ServiceAccountsWrite) && !serviceAccount.tokens && ( )} {contextSrv.hasPermissionInMetadata(AccessControlAction.ServiceAccountsWrite, serviceAccount) && (serviceAccount.isDisabled ? ( ) : ( ))} {contextSrv.hasPermissionInMetadata(AccessControlAction.ServiceAccountsDelete, serviceAccount) && ( onRemoveButtonClick(serviceAccount)} tooltip={`Delete service account ${serviceAccount.name}`} /> )} )} {serviceAccount.isExternal && ( )} ); } ); ServiceAccountListItemComponent.displayName = 'ServiceAccountListItem'; const ServiceAccountsListItemSkeleton: SkeletonComponent = ({ rootProps }) => { const styles = useStyles2(getSkeletonStyles); return ( ); }; const ServiceAccountListItem = attachSkeleton(ServiceAccountListItemComponent, ServiceAccountsListItemSkeleton); const getSkeletonStyles = (theme: GrafanaTheme2) => ({ blockSkeleton: css({ display: 'block', lineHeight: 1, }), deleteButton: css({ marginRight: theme.spacing(0.5), }), }); const getStyles = (theme: GrafanaTheme2) => { return { iconRow: css({ svg: { marginLeft: theme.spacing(0.5), }, }), accountId: cx( 'ellipsis', css({ color: theme.colors.text.secondary, }) ), deleteButton: css({ color: theme.colors.text.secondary, }), tokensInfo: css({ span: { marginRight: theme.spacing(1), }, }), tokensInfoSecondary: css({ color: theme.colors.text.secondary, }), disabled: css({ 'td a': { color: theme.colors.text.secondary, }, }), actionButton: css({ minWidth: 85, }), }; }; export default ServiceAccountListItem;