The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/public/app/core/components/RolePicker/RolePickerMenu.tsx

610 lines
18 KiB

Add new role picker to admin/users page (#40631) * Very simple role picker * Style radio button * Separate component for the built-in roles selector * Custom component instead of Select * refactor * Custom input for role picker * Refactor * Able to select built-in role * Add checkboxes for role selector * Filter out fixed and internal roles * Add action buttons * Implement role search * Fix selecting roles * Pass custom roles to update * User role picker * Some UX work on role picker * Clear search query on close * Blur input when closed * Add roles counter * Refactor * Add disabled state for picker * Adjust disabled styles * Replace ChangeOrgButton with role picker on admin/users page * Remove unused code * Apply suggestions from code review Suggestions from the @Clarity-89 Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com> * Refactor: fix some errors after applying review suggestions * Show fixed roles in the picker * Show applied fixed roles * Fix role counter * Fix checkbox selection * Use specific Role type for menu options * Fix menu when roles list is empty * Fix radio button name * Make fixed roles from built-in role disabled * Make whole menu scrollable * Add BuiltInRole type * Simplify appliedRoles * Simplify options and props * Do not select and disable inherited fixed roles * Enable selecting fixed role * Add description tooltip * Fix role param name * Export common input styles from grafana/ui * Add ValueContainer * Use value container * Refactor appliedRoles logic * Optimise role rendering * Display selected roles * Fix tooltip position * Use OrgRole type * Optimise role rendering * Use radio button from grafana UI * Submenu WIP * Role picker submenu WIP * Hide role description * Tweak styles * Implement submenu selection * Disable role selection if it's inherited * Show new role picker only in Enterprise * Fix types * Use orgid when fetching/updating roles * Use orgId in all access control requests * Styles for partially checked checkbox * Tweak group option styles * Role picker menu: refactor * Reorganize roles in menu * Fix input behaviour * Hide groups on search * Remove unused components * Refactor * Fix group selection * Remove icons from role tags * Add spacing for menu sections * Rename clear all to clear in submenu * Tweak menu width * Show changes in the input when selecting roles * Exclude inherited roles from selection * Increase menu height * Change built-in role in input on select * Include inherited roles to the built-in role selection * refcator import * Refactor role picker to be able to pass roles and builtin roles getters * Add role picker to the org users page * Show inherited builtin roles in the popup * Filter out managed roles * Fix displaying initial builtin roles * Show tooltip only for non-builtin roles * Set min width for focused input * Do not disable inherited roles (by design) * Only show picker if access control enabled * Fix tests * Only close menu on click outside or on indicator click * Open submenu on hover * Don't search on empty query * Do not open/close menu on click * Refactor * Apply suggestions from code review Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com> * Fix formatting * Apply suggestions * Add more space for close menu sign * Tune tooltip styles * Move tooltip to the right side of option * Use info sign instead of question Co-authored-by: Clarity-89 <homes89@ukr.net> Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>
4 years ago
import React, { FormEvent, useEffect, useRef, useState } from 'react';
import { css, cx } from '@emotion/css';
import {
Button,
Checkbox,
CustomScrollbar,
HorizontalGroup,
Icon,
Portal,
RadioButtonGroup,
Tooltip,
useStyles2,
useTheme2,
} from '@grafana/ui';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { getSelectStyles } from '@grafana/ui/src/components/Select/getSelectStyles';
import { OrgRole, Role } from 'app/types';
type BuiltInRoles = Record<string, Role[]>;
const BuiltinRoles = Object.values(OrgRole);
const BuiltinRoleOption: Array<SelectableValue<OrgRole>> = BuiltinRoles.map((r) => ({
label: r,
value: r,
}));
const fixedRoleGroupNames: Record<string, string> = {
ldap: 'LDAP',
current: 'Current org',
};
interface RolePickerMenuProps {
builtInRole: OrgRole;
builtInRoles: BuiltInRoles;
options: Role[];
appliedRoles: Role[];
showGroups?: boolean;
onSelect: (roles: Role[]) => void;
onBuiltInRoleSelect?: (role: OrgRole) => void;
onUpdate: (newBuiltInRole: OrgRole, newRoles: string[]) => void;
onClear?: () => void;
}
export const RolePickerMenu = ({
builtInRole,
builtInRoles,
options,
appliedRoles,
showGroups,
onSelect,
onBuiltInRoleSelect,
onUpdate,
onClear,
}: RolePickerMenuProps): JSX.Element => {
const [selectedOptions, setSelectedOptions] = useState<Role[]>(appliedRoles);
const [selectedBuiltInRole, setSelectedBuiltInRole] = useState<OrgRole>(builtInRole);
const [showSubMenu, setShowSubMenu] = useState(false);
const [openedMenuGroup, setOpenedMenuGroup] = useState('');
const [subMenuOptions, setSubMenuOptions] = useState<Role[]>([]);
const subMenuNode = useRef<HTMLDivElement | null>(null);
const theme = useTheme2();
const styles = getSelectStyles(theme);
const customStyles = useStyles2(getStyles);
// Call onSelect() on every selectedOptions change
useEffect(() => {
onSelect(selectedOptions);
}, [selectedOptions, onSelect]);
useEffect(() => {
if (onBuiltInRoleSelect) {
onBuiltInRoleSelect(selectedBuiltInRole);
}
}, [selectedBuiltInRole, onBuiltInRoleSelect]);
const customRoles = options.filter(filterCustomRoles).sort(sortRolesByName);
const fixedRoles = options.filter(filterFixedRoles).sort(sortRolesByName);
const optionGroups = getOptionGroups(options);
const getSelectedGroupOptions = (group: string) => {
const selectedGroupOptions = [];
for (const role of selectedOptions) {
if (getRoleGroup(role) === group) {
selectedGroupOptions.push(role);
}
}
return selectedGroupOptions;
};
const groupSelected = (group: string) => {
const selectedGroupOptions = getSelectedGroupOptions(group);
const groupOptions = optionGroups.find((g) => g.value === group);
return selectedGroupOptions.length > 0 && selectedGroupOptions.length >= groupOptions!.options.length;
};
const groupPartiallySelected = (group: string) => {
const selectedGroupOptions = getSelectedGroupOptions(group);
const groupOptions = optionGroups.find((g) => g.value === group);
return selectedGroupOptions.length > 0 && selectedGroupOptions.length < groupOptions!.options.length;
};
const onChange = (option: Role) => {
if (selectedOptions.find((role) => role.uid === option.uid)) {
setSelectedOptions(selectedOptions.filter((role) => role.uid !== option.uid));
} else {
setSelectedOptions([...selectedOptions, option]);
}
};
const onGroupChange = (value: string) => {
const group = optionGroups.find((g) => {
return g.value === value;
});
if (groupSelected(value)) {
if (group) {
setSelectedOptions(selectedOptions.filter((role) => !group.options.find((option) => role.uid === option.uid)));
}
} else {
if (group) {
const restOptions = selectedOptions.filter((role) => !group.options.find((option) => role.uid === option.uid));
setSelectedOptions([...restOptions, ...group.options]);
}
}
};
const onOpenSubMenu = (value: string) => {
setOpenedMenuGroup(value);
setShowSubMenu(true);
const group = optionGroups.find((g) => {
return g.value === value;
});
if (group) {
setSubMenuOptions(group.options);
}
};
const onCloseSubMenu = (value: string) => {
setShowSubMenu(false);
setOpenedMenuGroup('');
setSubMenuOptions([]);
};
const onSelectedBuiltinRoleChange = (newRole: OrgRole) => {
setSelectedBuiltInRole(newRole);
};
const onClearInternal = async () => {
if (onClear) {
onClear();
}
setSelectedOptions([]);
};
const onClearSubMenu = () => {
const options = selectedOptions.filter((role) => {
const groupName = getRoleGroup(role);
return groupName !== openedMenuGroup;
});
setSelectedOptions(options);
};
const onUpdateInternal = () => {
const selectedCustomRoles: string[] = [];
for (const key in selectedOptions) {
const roleUID = selectedOptions[key]?.uid;
selectedCustomRoles.push(roleUID);
}
onUpdate(selectedBuiltInRole, selectedCustomRoles);
};
return (
<div className={cx(styles.menu, customStyles.menuWrapper)}>
<div className={customStyles.menu} aria-label="Role picker menu">
<CustomScrollbar autoHide={false} autoHeightMax="300px" hideHorizontalTrack hideVerticalTrack>
<div className={customStyles.menuSection}>
<div className={customStyles.groupHeader}>Built-in roles</div>
<RadioButtonGroup
className={customStyles.builtInRoleSelector}
options={BuiltinRoleOption}
value={selectedBuiltInRole}
onChange={onSelectedBuiltinRoleChange}
fullWidth={true}
/>
</div>
{!!fixedRoles.length &&
(showGroups && !!optionGroups.length ? (
<div className={customStyles.menuSection}>
<div className={customStyles.groupHeader}>Fixed roles</div>
<div className={styles.optionBody}>
{optionGroups.map((option, i) => (
<RoleMenuGroupOption
data={option}
key={i}
isSelected={groupSelected(option.value) || groupPartiallySelected(option.value)}
partiallySelected={groupPartiallySelected(option.value)}
onChange={onGroupChange}
onOpenSubMenu={onOpenSubMenu}
onCloseSubMenu={onCloseSubMenu}
root={subMenuNode?.current!}
isFocused={showSubMenu && openedMenuGroup === option.value}
>
{showSubMenu && openedMenuGroup === option.value && (
<RolePickerSubMenu
options={subMenuOptions}
selectedOptions={selectedOptions}
onSelect={onChange}
onClear={onClearSubMenu}
/>
)}
</RoleMenuGroupOption>
))}
</div>
</div>
) : (
<div className={customStyles.menuSection}>
<div className={customStyles.groupHeader}>Fixed roles</div>
<div className={styles.optionBody}>
{fixedRoles.map((option, i) => (
<RoleMenuOption
data={option}
key={i}
isSelected={!!(option.uid && !!selectedOptions.find((opt) => opt.uid === option.uid))}
onChange={onChange}
hideDescription
/>
))}
</div>
</div>
))}
{!!customRoles.length && (
<div>
<div className={customStyles.groupHeader}>Custom roles</div>
<div className={styles.optionBody}>
{customRoles.map((option, i) => (
<RoleMenuOption
data={option}
key={i}
isSelected={!!(option.uid && !!selectedOptions.find((opt) => opt.uid === option.uid))}
onChange={onChange}
hideDescription
/>
))}
</div>
</div>
)}
</CustomScrollbar>
<div className={customStyles.menuButtonRow}>
<HorizontalGroup justify="flex-end">
<Button size="sm" fill="text" onClick={onClearInternal}>
Clear all
</Button>
<Button size="sm" onClick={onUpdateInternal}>
Update
</Button>
</HorizontalGroup>
</div>
</div>
<div ref={subMenuNode}></div>
</div>
);
};
const filterCustomRoles = (option: Role) => !option.name?.startsWith('fixed:');
const filterFixedRoles = (option: Role) => option.name?.startsWith('fixed:');
const getOptionGroups = (options: Role[]) => {
const groupsMap: { [key: string]: Role[] } = {};
options.forEach((role) => {
if (role.name.startsWith('fixed:')) {
const groupName = getRoleGroup(role);
if (groupsMap[groupName]) {
groupsMap[groupName].push(role);
} else {
groupsMap[groupName] = [role];
}
}
});
const groups = [];
for (const groupName of Object.keys(groupsMap)) {
const groupOptions = groupsMap[groupName].sort(sortRolesByName);
groups.push({
name: fixedRoleGroupNames[groupName] || capitalize(groupName),
value: groupName,
options: groupOptions,
});
}
return groups.sort((a, b) => a.name.localeCompare(b.name));
};
interface RolePickerSubMenuProps {
options: Role[];
selectedOptions: Role[];
disabledOptions?: Role[];
onSelect: (option: Role) => void;
onClear?: () => void;
}
export const RolePickerSubMenu = ({
options,
selectedOptions,
disabledOptions,
onSelect,
onClear,
}: RolePickerSubMenuProps): JSX.Element => {
const theme = useTheme2();
const styles = getSelectStyles(theme);
const customStyles = useStyles2(getStyles);
const onClearInternal = async () => {
if (onClear) {
onClear();
}
};
return (
<div className={customStyles.subMenu} aria-label="Role picker submenu">
<CustomScrollbar autoHide={false} autoHeightMax="300px" hideHorizontalTrack>
<div className={styles.optionBody}>
{options.map((option, i) => (
<RoleMenuOption
data={option}
key={i}
isSelected={
!!(
option.uid &&
(!!selectedOptions.find((opt) => opt.uid === option.uid) ||
disabledOptions?.find((opt) => opt.uid === option.uid))
)
}
disabled={!!(option.uid && disabledOptions?.find((opt) => opt.uid === option.uid))}
onChange={onSelect}
hideDescription
/>
))}
</div>
</CustomScrollbar>
<div className={customStyles.subMenuButtonRow}>
<HorizontalGroup justify="flex-end">
<Button size="sm" fill="text" onClick={onClearInternal}>
Clear
</Button>
</HorizontalGroup>
</div>
</div>
);
};
interface RoleMenuOptionProps<T> {
data: Role;
onChange: (value: Role) => void;
isSelected?: boolean;
isFocused?: boolean;
disabled?: boolean;
hideDescription?: boolean;
}
export const RoleMenuOption = React.forwardRef<HTMLDivElement, React.PropsWithChildren<RoleMenuOptionProps<any>>>(
({ data, isFocused, isSelected, disabled, onChange, hideDescription }, ref) => {
const theme = useTheme2();
const styles = getSelectStyles(theme);
const customStyles = useStyles2(getStyles);
const wrapperClassName = cx(
styles.option,
isFocused && styles.optionFocused,
disabled && customStyles.menuOptionDisabled
);
const onChangeInternal = (event: FormEvent<HTMLElement>) => {
if (disabled) {
return;
}
event.preventDefault();
event.stopPropagation();
onChange(data);
};
return (
<div ref={ref} className={wrapperClassName} aria-label="Role picker option" onClick={onChangeInternal}>
<Checkbox
value={isSelected}
className={customStyles.menuOptionCheckbox}
onChange={onChangeInternal}
disabled={disabled}
/>
<div className={cx(styles.optionBody, customStyles.menuOptionBody)}>
<span>{data.displayName || data.name}</span>
{!hideDescription && data.description && <div className={styles.optionDescription}>{data.description}</div>}
</div>
{data.description && (
<Tooltip content={data.description}>
<Icon name="info-circle" className={customStyles.menuOptionInfoSign} />
</Tooltip>
)}
</div>
);
}
);
RoleMenuOption.displayName = 'RoleMenuOption';
interface RoleMenuGroupsOptionProps {
data: SelectableValue<string>;
onChange: (value: string) => void;
onClick?: (value: string) => void;
onOpenSubMenu?: (value: string) => void;
onCloseSubMenu?: (value: string) => void;
isSelected?: boolean;
partiallySelected?: boolean;
isFocused?: boolean;
disabled?: boolean;
children?: React.ReactNode;
root?: HTMLElement;
}
export const RoleMenuGroupOption = React.forwardRef<HTMLDivElement, RoleMenuGroupsOptionProps>(
(
{
data,
isFocused,
isSelected,
partiallySelected,
disabled,
onChange,
onClick,
onOpenSubMenu,
onCloseSubMenu,
children,
root,
},
ref
) => {
const theme = useTheme2();
const styles = getSelectStyles(theme);
const customStyles = useStyles2(getStyles);
const wrapperClassName = cx(
styles.option,
isFocused && styles.optionFocused,
disabled && customStyles.menuOptionDisabled
);
const onChangeInternal = (event: FormEvent<HTMLElement>) => {
if (disabled) {
return;
}
if (data.value) {
onChange(data.value);
}
};
const onClickInternal = (event: FormEvent<HTMLElement>) => {
if (onClick) {
onClick(data.value!);
}
};
const onMouseEnter = () => {
if (onOpenSubMenu) {
onOpenSubMenu(data.value!);
}
};
const onMouseLeave = () => {
if (onCloseSubMenu) {
onCloseSubMenu(data.value!);
}
};
return (
<div onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
<div ref={ref} className={wrapperClassName} aria-label="Role picker option" onClick={onClickInternal}>
<Checkbox
value={isSelected}
className={cx(customStyles.menuOptionCheckbox, {
[customStyles.checkboxPartiallyChecked]: partiallySelected,
})}
onChange={onChangeInternal}
disabled={disabled}
/>
<div className={cx(styles.optionBody, customStyles.menuOptionBody)}>
<span>{data.displayName || data.name}</span>
<span className={customStyles.menuOptionExpand}></span>
</div>
{root && children && (
<Portal className={customStyles.subMenuPortal} root={root}>
{children}
</Portal>
)}
</div>
</div>
);
}
);
RoleMenuGroupOption.displayName = 'RoleMenuGroupOption';
const getRoleGroup = (role: Role) => {
return role.group ?? 'Other';
Add new role picker to admin/users page (#40631) * Very simple role picker * Style radio button * Separate component for the built-in roles selector * Custom component instead of Select * refactor * Custom input for role picker * Refactor * Able to select built-in role * Add checkboxes for role selector * Filter out fixed and internal roles * Add action buttons * Implement role search * Fix selecting roles * Pass custom roles to update * User role picker * Some UX work on role picker * Clear search query on close * Blur input when closed * Add roles counter * Refactor * Add disabled state for picker * Adjust disabled styles * Replace ChangeOrgButton with role picker on admin/users page * Remove unused code * Apply suggestions from code review Suggestions from the @Clarity-89 Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com> * Refactor: fix some errors after applying review suggestions * Show fixed roles in the picker * Show applied fixed roles * Fix role counter * Fix checkbox selection * Use specific Role type for menu options * Fix menu when roles list is empty * Fix radio button name * Make fixed roles from built-in role disabled * Make whole menu scrollable * Add BuiltInRole type * Simplify appliedRoles * Simplify options and props * Do not select and disable inherited fixed roles * Enable selecting fixed role * Add description tooltip * Fix role param name * Export common input styles from grafana/ui * Add ValueContainer * Use value container * Refactor appliedRoles logic * Optimise role rendering * Display selected roles * Fix tooltip position * Use OrgRole type * Optimise role rendering * Use radio button from grafana UI * Submenu WIP * Role picker submenu WIP * Hide role description * Tweak styles * Implement submenu selection * Disable role selection if it's inherited * Show new role picker only in Enterprise * Fix types * Use orgid when fetching/updating roles * Use orgId in all access control requests * Styles for partially checked checkbox * Tweak group option styles * Role picker menu: refactor * Reorganize roles in menu * Fix input behaviour * Hide groups on search * Remove unused components * Refactor * Fix group selection * Remove icons from role tags * Add spacing for menu sections * Rename clear all to clear in submenu * Tweak menu width * Show changes in the input when selecting roles * Exclude inherited roles from selection * Increase menu height * Change built-in role in input on select * Include inherited roles to the built-in role selection * refcator import * Refactor role picker to be able to pass roles and builtin roles getters * Add role picker to the org users page * Show inherited builtin roles in the popup * Filter out managed roles * Fix displaying initial builtin roles * Show tooltip only for non-builtin roles * Set min width for focused input * Do not disable inherited roles (by design) * Only show picker if access control enabled * Fix tests * Only close menu on click outside or on indicator click * Open submenu on hover * Don't search on empty query * Do not open/close menu on click * Refactor * Apply suggestions from code review Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com> * Fix formatting * Apply suggestions * Add more space for close menu sign * Tune tooltip styles * Move tooltip to the right side of option * Use info sign instead of question Co-authored-by: Clarity-89 <homes89@ukr.net> Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>
4 years ago
};
const capitalize = (s: string): string => {
return s.slice(0, 1).toUpperCase() + s.slice(1);
};
const sortRolesByName = (a: Role, b: Role) => a.name.localeCompare(b.name);
export const getStyles = (theme: GrafanaTheme2) => {
return {
menuWrapper: css`
display: flex;
max-height: 650px;
position: absolute;
z-index: ${theme.zIndex.dropdown};
overflow: hidden;
min-width: auto;
`,
menu: css`
min-width: 260px;
& > div {
padding-top: ${theme.spacing(1)};
}
`,
subMenu: css`
height: 100%;
min-width: 260px;
display: flex;
flex-direction: column;
border-left-style: solid;
border-left-width: 1px;
border-left-color: ${theme.components.input.borderColor};
& > div {
padding-top: ${theme.spacing(1)};
}
`,
groupHeader: css`
padding: ${theme.spacing(0, 4)};
display: flex;
align-items: center;
color: ${theme.colors.text.primary};
font-weight: ${theme.typography.fontWeightBold};
`,
container: css`
padding: ${theme.spacing(1)};
border: 1px ${theme.colors.border.weak} solid;
border-radius: ${theme.shape.borderRadius(1)};
background-color: ${theme.colors.background.primary};
z-index: ${theme.zIndex.modal};
`,
menuSection: css`
margin-bottom: ${theme.spacing(2)};
`,
menuOptionCheckbox: css`
display: flex;
margin: ${theme.spacing(0, 1, 0, 0.25)};
`,
menuButtonRow: css`
background-color: ${theme.colors.background.primary};
padding: ${theme.spacing(1)};
`,
menuOptionBody: css`
font-weight: ${theme.typography.fontWeightRegular};
padding: ${theme.spacing(0, 1.5, 0, 0)};
Add new role picker to admin/users page (#40631) * Very simple role picker * Style radio button * Separate component for the built-in roles selector * Custom component instead of Select * refactor * Custom input for role picker * Refactor * Able to select built-in role * Add checkboxes for role selector * Filter out fixed and internal roles * Add action buttons * Implement role search * Fix selecting roles * Pass custom roles to update * User role picker * Some UX work on role picker * Clear search query on close * Blur input when closed * Add roles counter * Refactor * Add disabled state for picker * Adjust disabled styles * Replace ChangeOrgButton with role picker on admin/users page * Remove unused code * Apply suggestions from code review Suggestions from the @Clarity-89 Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com> * Refactor: fix some errors after applying review suggestions * Show fixed roles in the picker * Show applied fixed roles * Fix role counter * Fix checkbox selection * Use specific Role type for menu options * Fix menu when roles list is empty * Fix radio button name * Make fixed roles from built-in role disabled * Make whole menu scrollable * Add BuiltInRole type * Simplify appliedRoles * Simplify options and props * Do not select and disable inherited fixed roles * Enable selecting fixed role * Add description tooltip * Fix role param name * Export common input styles from grafana/ui * Add ValueContainer * Use value container * Refactor appliedRoles logic * Optimise role rendering * Display selected roles * Fix tooltip position * Use OrgRole type * Optimise role rendering * Use radio button from grafana UI * Submenu WIP * Role picker submenu WIP * Hide role description * Tweak styles * Implement submenu selection * Disable role selection if it's inherited * Show new role picker only in Enterprise * Fix types * Use orgid when fetching/updating roles * Use orgId in all access control requests * Styles for partially checked checkbox * Tweak group option styles * Role picker menu: refactor * Reorganize roles in menu * Fix input behaviour * Hide groups on search * Remove unused components * Refactor * Fix group selection * Remove icons from role tags * Add spacing for menu sections * Rename clear all to clear in submenu * Tweak menu width * Show changes in the input when selecting roles * Exclude inherited roles from selection * Increase menu height * Change built-in role in input on select * Include inherited roles to the built-in role selection * refcator import * Refactor role picker to be able to pass roles and builtin roles getters * Add role picker to the org users page * Show inherited builtin roles in the popup * Filter out managed roles * Fix displaying initial builtin roles * Show tooltip only for non-builtin roles * Set min width for focused input * Do not disable inherited roles (by design) * Only show picker if access control enabled * Fix tests * Only close menu on click outside or on indicator click * Open submenu on hover * Don't search on empty query * Do not open/close menu on click * Refactor * Apply suggestions from code review Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com> * Fix formatting * Apply suggestions * Add more space for close menu sign * Tune tooltip styles * Move tooltip to the right side of option * Use info sign instead of question Co-authored-by: Clarity-89 <homes89@ukr.net> Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>
4 years ago
`,
menuOptionDisabled: css`
color: ${theme.colors.text.disabled};
cursor: not-allowed;
`,
menuOptionExpand: css`
position: absolute;
right: ${theme.spacing(1.25)};
color: ${theme.colors.text.disabled};
&:after {
content: '>';
}
`,
menuOptionInfoSign: css`
color: ${theme.colors.text.disabled};
`,
builtInRoleSelector: css`
margin: ${theme.spacing(1, 1.25, 1, 1)};
`,
subMenuPortal: css`
height: 100%;
> div {
height: 100%;
}
`,
subMenuButtonRow: css`
background-color: ${theme.colors.background.primary};
padding: ${theme.spacing(1)};
`,
checkboxPartiallyChecked: css`
input {
&:checked + span {
&:after {
border-width: 0 3px 0px 0;
transform: rotate(90deg);
}
}
}
`,
};
};