Team LBAC: Show permissions warning (#80215)

* Permissions: Add team LBAC warnings

* Replace info with warning if present

* Keep info message

* Update warning message

* Translate permission warning

* Use box component

* Generate translation placeholder

* Use multiple messages

* Move LBAC warnings to enterprise
This commit is contained in:
Alexander Zobnin 2024-01-11 14:48:55 +03:00 committed by GitHub
parent cc5a573ce0
commit bb2156967d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 71 additions and 39 deletions

View File

@ -1,6 +1,8 @@
import { css } from '@emotion/css';
import React from 'react'; import React from 'react';
import { Button, Icon, Select, Tooltip } from '@grafana/ui'; import { GrafanaTheme2 } from '@grafana/data';
import { Box, Button, Icon, Select, Tooltip, useStyles2 } from '@grafana/ui';
import { ResourcePermission } from './types'; import { ResourcePermission } from './types';
@ -12,42 +14,59 @@ interface Props {
onChange: (item: ResourcePermission, permission: string) => void; onChange: (item: ResourcePermission, permission: string) => void;
} }
export const PermissionListItem = ({ item, permissionLevels, canSet, onRemove, onChange }: Props) => ( export const PermissionListItem = ({ item, permissionLevels, canSet, onRemove, onChange }: Props) => {
<tr> const styles = useStyles2(getStyles);
<td>{getAvatar(item)}</td>
<td>{getDescription(item)}</td> return (
<td>{item.isInherited && <em className="muted no-wrap">Inherited from folder</em>}</td> <tr>
<td> <td>{getAvatar(item)}</td>
<Select <td>{getDescription(item)}</td>
disabled={!canSet || !item.isManaged} <td>{item.isInherited && <em className="muted no-wrap">Inherited from folder</em>}</td>
onChange={(p) => onChange(item, p.value!)} <td>
value={permissionLevels.find((p) => p === item.permission)} <Select
options={permissionLevels.map((p) => ({ value: p, label: p }))} disabled={!canSet || !item.isManaged}
/> onChange={(p) => onChange(item, p.value!)}
</td> value={permissionLevels.find((p) => p === item.permission)}
<td> options={permissionLevels.map((p) => ({ value: p, label: p }))}
<Tooltip content={getPermissionInfo(item)}>
<Icon name="info-circle" />
</Tooltip>
</td>
<td>
{item.isManaged ? (
<Button
size="sm"
icon="times"
variant="destructive"
disabled={!canSet}
onClick={() => onRemove(item)}
aria-label={`Remove permission for ${getName(item)}`}
/> />
) : ( </td>
<Tooltip content={item.isInherited ? 'Inherited Permission' : 'Provisioned Permission'}> <td>
<Button size="sm" icon="lock" /> {item.warning ? (
</Tooltip> <Tooltip
)} content={
</td> <>
</tr> <Box marginBottom={1}>{item.warning}</Box>
); {getPermissionInfo(item)}
</>
}
>
<Icon name="exclamation-triangle" className={styles.warning} />
</Tooltip>
) : (
<Tooltip content={getPermissionInfo(item)}>
<Icon name="info-circle" />
</Tooltip>
)}
</td>
<td>
{item.isManaged ? (
<Button
size="sm"
icon="times"
variant="destructive"
disabled={!canSet}
onClick={() => onRemove(item)}
aria-label={`Remove permission for ${getName(item)}`}
/>
) : (
<Tooltip content={item.isInherited ? 'Inherited Permission' : 'Provisioned Permission'}>
<Button size="sm" icon="lock" />
</Tooltip>
)}
</td>
</tr>
);
};
const getAvatar = (item: ResourcePermission) => { const getAvatar = (item: ResourcePermission) => {
if (item.teamId) { if (item.teamId) {
@ -80,3 +99,9 @@ const getDescription = (item: ResourcePermission) => {
}; };
const getPermissionInfo = (p: ResourcePermission) => `Actions: ${[...new Set(p.actions)].sort().join(' ')}`; const getPermissionInfo = (p: ResourcePermission) => `Actions: ${[...new Set(p.actions)].sort().join(' ')}`;
const getStyles = (theme: GrafanaTheme2) => ({
warning: css({
color: theme.colors.warning.main,
}),
});

View File

@ -37,6 +37,7 @@ export type Props = {
resource: string; resource: string;
resourceId: ResourceId; resourceId: ResourceId;
canSetPermissions: boolean; canSetPermissions: boolean;
getWarnings?: (items: ResourcePermission[]) => ResourcePermission[];
}; };
export const Permissions = ({ export const Permissions = ({
@ -47,15 +48,20 @@ export const Permissions = ({
resourceId, resourceId,
canSetPermissions, canSetPermissions,
addPermissionTitle, addPermissionTitle,
getWarnings,
}: Props) => { }: Props) => {
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
const [isAdding, setIsAdding] = useState(false); const [isAdding, setIsAdding] = useState(false);
const [items, setItems] = useState<ResourcePermission[]>([]); const [items, setItems] = useState<ResourcePermission[]>([]);
const [desc, setDesc] = useState(INITIAL_DESCRIPTION); const [desc, setDesc] = useState(INITIAL_DESCRIPTION);
const fetchItems = useCallback(() => { const fetchItems = useCallback(async () => {
return getPermissions(resource, resourceId).then((r) => setItems(r)); let items = await getPermissions(resource, resourceId);
}, [resource, resourceId]); if (getWarnings) {
items = getWarnings(items);
}
setItems(items);
}, [resource, resourceId, getWarnings]);
useEffect(() => { useEffect(() => {
getDescription(resource).then((r) => { getDescription(resource).then((r) => {

View File

@ -13,6 +13,7 @@ export type ResourcePermission = {
builtInRole?: string; builtInRole?: string;
actions: string[]; actions: string[];
permission: string; permission: string;
warning?: string;
}; };
export type SetPermission = { export type SetPermission = {