import { css, cx } from '@emotion/css'; import { FormEvent, HTMLProps, useEffect, useRef } from 'react'; import * as React from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { Trans, t } from '@grafana/i18n'; import { useStyles2, getInputStyles, sharedInputStyle, Tooltip, Icon, Spinner } from '@grafana/ui'; import { getFocusStyles } from '@grafana/ui/internal'; import { Role } from '../../../types'; import { ValueContainer } from './ValueContainer'; import { ROLE_PICKER_WIDTH } from './constants'; const stopPropagation = (event: React.MouseEvent) => event.stopPropagation(); interface InputProps extends HTMLProps { appliedRoles: Role[]; basicRole?: string; query: string; showBasicRole?: boolean; isFocused?: boolean; disabled?: boolean; width?: string; isLoading?: boolean; onQueryChange: (query?: string) => void; onOpen: (event: FormEvent) => void; onClose: () => void; } export const RolePickerInput = ({ appliedRoles, basicRole, disabled, isFocused, query, showBasicRole, width, isLoading, onOpen, onClose, onQueryChange, ...rest }: InputProps): JSX.Element => { const styles = useStyles2(getRolePickerInputStyles, false, !!isFocused, !!disabled, false, width); const inputRef = useRef(null); useEffect(() => { if (isFocused) { inputRef.current?.focus(); } }); const onInputChange = (event: React.ChangeEvent) => { const query = event.target?.value; onQueryChange(query); }; const showBasicRoleOnLabel = showBasicRole && basicRole !== 'None'; return !isFocused ? ( // TODO: fix keyboard a11y // eslint-disable-next-line jsx-a11y/no-static-element-interactions
{showBasicRoleOnLabel && {basicRole}} {isLoading && (
)}
) : (
{showBasicRoleOnLabel && {basicRole}} {appliedRoles.map((role) => ( {role.group + ':' + (role.displayName || role.name)} ))} {!disabled && ( )}
); }; RolePickerInput.displayName = 'RolePickerInput'; interface RolesLabelProps { appliedRoles: Role[]; showBuiltInRole?: boolean; numberOfRoles: number; } export const RolesLabel = ({ showBuiltInRole, numberOfRoles, appliedRoles }: RolesLabelProps): JSX.Element => { const styles = useStyles2((theme) => getTooltipStyles(theme)); return ( <> {!!numberOfRoles ? ( {appliedRoles?.map((role) =>

{role.group + ':' + (role.displayName || role.name)}

)} } > {`${showBuiltInRole ? '+' : ''}${numberOfRoles} role${ numberOfRoles > 1 ? 's' : '' }`}
) : ( !showBuiltInRole && ( No roles assigned ) )} ); }; const getRolePickerInputStyles = ( theme: GrafanaTheme2, invalid: boolean, focused: boolean, disabled: boolean, withPrefix: boolean, width?: string ) => { const styles = getInputStyles({ theme, invalid }); return { wrapper: cx( styles.wrapper, sharedInputStyle(theme, invalid), focused && css(getFocusStyles(theme)), disabled && styles.inputDisabled, css({ minWidth: width || ROLE_PICKER_WIDTH + 'px', width: width, minHeight: '32px', maxHeight: '200px', overflow: 'scroll', overflowX: 'hidden', overflowY: 'auto', height: 'auto', flexDirection: 'row', paddingRight: theme.spacing(1), maxWidth: '100%', alignItems: 'center', display: 'flex', flexWrap: 'wrap', justifyContent: 'flex-start', position: 'relative', boxSizing: 'border-box', cursor: 'default', }), withPrefix && css({ paddingLeft: 0, }) ), input: cx( sharedInputStyle(theme, invalid), css({ maxWidth: '120px', border: 'none', cursor: focused ? 'default' : 'pointer', }) ), suffix: styles.suffix, dropdownIndicator: css({ cursor: 'pointer', }), selectedRoles: css({ display: 'flex', alignItems: 'center', cursor: disabled ? 'not-allowed' : 'pointer', }), tooltip: css({ p: { marginBottom: theme.spacing(0.5), }, }), spinner: css({ display: 'flex', flexGrow: 1, justifyContent: 'flex-end', }), }; }; const getTooltipStyles = (theme: GrafanaTheme2) => ({ tooltip: css({ p: { marginBottom: theme.spacing(0.5), }, }), });