Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"@emotion/cache": "^11.14.0",
"@eslint/eslintrc": "^3.3.5",
"@eslint/js": "^10.0.1",
"@meshery/schemas": "1.3.13",
"@meshery/schemas": "^1.3.25",
"@mui/icons-material": "^9.0.0",
"@mui/material": "^9.0.0",
"@mui/system": "^9.0.0",
Expand Down
43 changes: 31 additions & 12 deletions src/base/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,56 @@
import { Button as MuiButton, type ButtonProps as MuiButtonProps } from '@mui/material';
import React from 'react';
import { useHasPermission, type PermissionAction } from '../../custom/PermissionProvider';
import { Key, PermissionShield } from '../../custom/permissions';

export interface ButtonProps extends MuiButtonProps {
label?: string;
children?: React.ReactNode;
permissionKey?: Key;
/**
* Determines behavior when the user lacks the required permission.
*
* - `'showShield'` (default) — disables the button and shows a shield icon
* with a permission-metadata tooltip.
* - `'hide'` — renders nothing.
*
* Ignored when `permissionKey` is not provided.
*/
permissionAction?: PermissionAction;
}

export function Button({
label,
children,
permissionKey,
permissionAction = 'showShield',
disabled,
...props
}: ButtonProps): JSX.Element {
// When disabled AND permissionKey is provided, show the shield overlay
if (disabled && permissionKey) {
const hasPermission = useHasPermission(permissionKey);
Comment thread
rishiraj38 marked this conversation as resolved.

// useHasPermission returns true when no permissionKey is provided (backward compatible)
if (hasPermission) {
return (
<PermissionShield permissionKey={permissionKey} variant="badge">
<MuiButton {...props} disabled={true}>
{label}
{children}
</MuiButton>
</PermissionShield>
<MuiButton {...props} disabled={disabled}>
{label}
{children}
</MuiButton>
);
}

// User LACKS permission → apply the permissionAction
if (permissionAction === 'hide') {
return <></>;
}

return (
<MuiButton {...props} disabled={disabled}>
{label}
{children}
</MuiButton>
<PermissionShield permissionKey={permissionKey!} variant="badge">
<MuiButton {...props} disabled={true}>
{label}
{children}
</MuiButton>
</PermissionShield>
);
}

Expand Down
35 changes: 26 additions & 9 deletions src/base/IconButton/IconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,42 @@ import {
type IconButtonProps as MuiIconButtonProps
} from '@mui/material';
import React from 'react';
import { useHasPermission, type PermissionAction } from '../../custom/PermissionProvider';
import { Key, PermissionShield } from '../../custom/permissions';

export interface IconButtonProps extends MuiIconButtonProps {
permissionKey?: Key;
/**
* Determines behavior when the user lacks the required permission.
*
* - `'showShield'` (default) — disables the button and shows a shield icon
* with a permission-metadata tooltip.
* - `'hide'` — renders nothing.
*
* Ignored when `permissionKey` is not provided.
*/
permissionAction?: PermissionAction;
}

export const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>((props, ref) => {
const { permissionKey, disabled, ...rest } = props;
const { permissionKey, permissionAction = 'showShield', disabled, ...rest } = props;
const hasPermission = useHasPermission(permissionKey);

// When disabled AND permissionKey is provided, show the shield overlay
if (disabled && permissionKey) {
return (
<PermissionShield permissionKey={permissionKey} variant="badge">
<MuiIconButton ref={ref} {...rest} disabled={true} />
</PermissionShield>
);
// useHasPermission returns true when no permissionKey is provided (backward compatible)
if (hasPermission) {
return <MuiIconButton ref={ref} {...rest} disabled={disabled} />;
}

return <MuiIconButton ref={ref} {...rest} disabled={disabled} />;
// User LACKS permission → apply the permissionAction
if (permissionAction === 'hide') {
return null;
}

return (
<PermissionShield permissionKey={permissionKey!} variant="badge">
<MuiIconButton ref={ref} {...rest} disabled={true} />
</PermissionShield>
);
});

IconButton.displayName = 'IconButton';
Expand Down
38 changes: 27 additions & 11 deletions src/base/ListItem/ListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,43 @@
import { ListItem as MuiListItem, ListItemProps as MuiListItemProps } from '@mui/material';
import React from 'react';
import { useHasPermission, type PermissionAction } from '../../custom/PermissionProvider';
import { Key, PermissionShield } from '../../custom/permissions';

export interface ListItemProps extends MuiListItemProps {
permissionKey?: Key;
disabled?: boolean;
/**
* Determines behavior when the user lacks the required permission.
*
* - `'showShield'` (default) — disables the item and shows a shield icon
* with a permission-metadata tooltip.
* - `'hide'` — renders nothing.
*
* Ignored when `permissionKey` is not provided.
*/
permissionAction?: PermissionAction;
}

const ListItem = React.forwardRef<HTMLLIElement, ListItemProps>((props, ref) => {
const { permissionKey, disabled, ...rest } = props;
const { permissionKey, permissionAction = 'showShield', ...rest } = props;
delete (rest as Record<string, unknown>).disabled;
const hasPermission = useHasPermission(permissionKey);

// When disabled AND permissionKey is provided, show the shield overlay
// Note: MUI ListItem doesn't have a native `disabled` prop, so we only use
// it as a custom guard for the PermissionShield wrapper
if (disabled && permissionKey) {
return (
<PermissionShield permissionKey={permissionKey} variant="inline">
<MuiListItem {...rest} ref={ref} />
</PermissionShield>
);
// useHasPermission returns true when no permissionKey is provided (backward compatible)
if (hasPermission) {
return <MuiListItem {...rest} ref={ref} />;
}

return <MuiListItem {...rest} ref={ref} />;
// User LACKS permission → apply the permissionAction
if (permissionAction === 'hide') {
return null;
}

return (
<PermissionShield permissionKey={permissionKey!} variant="inline">
<MuiListItem {...rest} ref={ref} />
</PermissionShield>
);
});

ListItem.displayName = 'ListItem';
Expand Down
35 changes: 26 additions & 9 deletions src/base/ListItemButton/ListItemButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,42 @@ import {
ListItemButtonProps as MuiListItemButtonProps
} from '@mui/material';
import React from 'react';
import { useHasPermission, type PermissionAction } from '../../custom/PermissionProvider';
import { Key, PermissionShield } from '../../custom/permissions';

export interface ListItemButtonProps extends MuiListItemButtonProps {
permissionKey?: Key;
/**
* Determines behavior when the user lacks the required permission.
*
* - `'showShield'` (default) — disables the button and shows a shield icon
* with a permission-metadata tooltip.
* - `'hide'` — renders nothing.
*
* Ignored when `permissionKey` is not provided.
*/
permissionAction?: PermissionAction;
}

const ListItemButton = React.forwardRef<HTMLDivElement, ListItemButtonProps>((props, ref) => {
const { permissionKey, disabled, ...rest } = props;
const { permissionKey, permissionAction = 'showShield', disabled, ...rest } = props;
const hasPermission = useHasPermission(permissionKey);

// When disabled AND permissionKey is provided, show the shield overlay
if (disabled && permissionKey) {
return (
<PermissionShield permissionKey={permissionKey} variant="inline">
<MuiListItemButton {...rest} ref={ref} disabled={true} />
</PermissionShield>
);
// useHasPermission returns true when no permissionKey is provided (backward compatible)
if (hasPermission) {
return <MuiListItemButton {...rest} ref={ref} disabled={disabled} />;
}

return <MuiListItemButton {...rest} ref={ref} disabled={disabled} />;
// User LACKS permission → apply the permissionAction
if (permissionAction === 'hide') {
return null;
}

return (
<PermissionShield permissionKey={permissionKey!} variant="inline">
<MuiListItemButton {...rest} ref={ref} disabled={true} />
</PermissionShield>
);
});

ListItemButton.displayName = 'ListItemButton';
Expand Down
35 changes: 26 additions & 9 deletions src/base/MenuItem/MenuItem.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,41 @@
import { MenuItem as MuiMenuItem, MenuItemProps as MuiMenuItemProps } from '@mui/material';
import React from 'react';
import { useHasPermission, type PermissionAction } from '../../custom/PermissionProvider';
import { Key, PermissionShield } from '../../custom/permissions';

export interface MenuItemProps extends MuiMenuItemProps {
permissionKey?: Key;
/**
* Determines behavior when the user lacks the required permission.
*
* - `'showShield'` (default) — disables the item and shows a shield icon
* with a permission-metadata tooltip.
* - `'hide'` — renders nothing.
*
* Ignored when `permissionKey` is not provided.
*/
permissionAction?: PermissionAction;
}

export function MenuItem(props: MenuItemProps): JSX.Element {
const { permissionKey, disabled, ...rest } = props;
const { permissionKey, permissionAction = 'showShield', disabled, ...rest } = props;
const hasPermission = useHasPermission(permissionKey);

// When disabled AND permissionKey is provided, show the shield overlay
if (disabled && permissionKey) {
return (
<PermissionShield permissionKey={permissionKey} variant="inline">
<MuiMenuItem {...rest} disabled={true} />
</PermissionShield>
);
// useHasPermission returns true when no permissionKey is provided (backward compatible)
if (hasPermission) {
return <MuiMenuItem {...rest} disabled={disabled} />;
}

return <MuiMenuItem {...rest} disabled={disabled} />;
// User LACKS permission → apply the permissionAction
if (permissionAction === 'hide') {
return <></>;
}

return (
<PermissionShield permissionKey={permissionKey!} variant="inline">
<MuiMenuItem {...rest} disabled={true} />
</PermissionShield>
);
}

export default MenuItem;
Loading
Loading