diff --git a/frontend/src/components/ACLPage/List/List.styled.ts b/frontend/src/components/ACLPage/List/List.styled.ts
index b1e8afead..01ca04407 100644
--- a/frontend/src/components/ACLPage/List/List.styled.ts
+++ b/frontend/src/components/ACLPage/List/List.styled.ts
@@ -7,9 +7,7 @@ export const EnumCell = styled.div`
`;
export const DeleteCell = styled.div`
- svg {
- cursor: pointer;
- }
+ display: flex;
`;
export const Chip = styled.div<{
diff --git a/frontend/src/components/ACLPage/List/List.tsx b/frontend/src/components/ACLPage/List/List.tsx
index c3ad4e3ad..f1a8298eb 100644
--- a/frontend/src/components/ACLPage/List/List.tsx
+++ b/frontend/src/components/ACLPage/List/List.tsx
@@ -24,6 +24,7 @@ import { ControlPanelWrapper } from 'components/common/ControlPanel/ControlPanel
import Search from 'components/common/Search/Search';
import ResourcePageHeading from 'components/common/ResourcePageHeading/ResourcePageHeading';
import BreakableTextCell from 'components/common/NewTable/BreakableTextCell';
+import { ActionPermissionWrapper } from 'components/common/ActionComponent';
import * as S from './List.styled';
@@ -150,13 +151,23 @@ const ACList: React.FC = () => {
// eslint-disable-next-line react/no-unstable-nested-components
cell: ({ row }) => {
return (
- handleDeleteClick(row.original)}>
-
-
+ handleDeleteClick(row.original)}
+ permission={{
+ resource: ResourceType.ACL,
+ action: Action.EDIT,
+ }}
+ >
+
+
+
+
);
},
size: 76,
diff --git a/frontend/src/components/common/ActionComponent/ActionComponent.styled.ts b/frontend/src/components/common/ActionComponent/ActionComponent.styled.ts
index ace26a048..85979db00 100644
--- a/frontend/src/components/common/ActionComponent/ActionComponent.styled.ts
+++ b/frontend/src/components/common/ActionComponent/ActionComponent.styled.ts
@@ -5,6 +5,7 @@ export const Wrapper = styled.div`
flex-direction: row;
align-items: center;
justify-content: center;
+ width: min-content;
`;
export const MessageTooltip = styled.div`
diff --git a/frontend/src/components/common/ActionComponent/ActionPermissionWrapper/ActionPermissionWrapper.tsx b/frontend/src/components/common/ActionComponent/ActionPermissionWrapper/ActionPermissionWrapper.tsx
new file mode 100644
index 000000000..7f0d16ae3
--- /dev/null
+++ b/frontend/src/components/common/ActionComponent/ActionPermissionWrapper/ActionPermissionWrapper.tsx
@@ -0,0 +1,57 @@
+import React, { ReactElement } from 'react';
+import {
+ ActionComponentProps,
+ getDefaultActionMessage,
+} from 'components/common/ActionComponent/ActionComponent';
+import { usePermission } from 'lib/hooks/usePermission';
+import { useActionTooltip } from 'lib/hooks/useActionTooltip';
+import * as S from 'components/common/ActionComponent/ActionComponent.styled';
+
+interface Props extends ActionComponentProps {
+ children: ReactElement;
+ onAction: () => void;
+}
+
+const ActionPermissionWrapper: React.FC = ({
+ permission,
+ onAction,
+ children,
+ placement,
+ message = getDefaultActionMessage(),
+}) => {
+ const canDoAction = usePermission(
+ permission.resource,
+ permission.action,
+ permission.value
+ );
+
+ const { x, y, refs, strategy, open } = useActionTooltip(
+ !canDoAction,
+ placement
+ );
+
+ return (
+ canDoAction && onAction()}
+ style={{ cursor: canDoAction ? 'pointer' : 'not-allowed' }}
+ >
+ {children}
+ {open && (
+
+ {message}
+
+ )}
+
+ );
+};
+
+export default ActionPermissionWrapper;
diff --git a/frontend/src/components/common/ActionComponent/ActionPermissionWrapper/__tests__/ActionPermissionWrapper.spec.tsx b/frontend/src/components/common/ActionComponent/ActionPermissionWrapper/__tests__/ActionPermissionWrapper.spec.tsx
new file mode 100644
index 000000000..44d8395ce
--- /dev/null
+++ b/frontend/src/components/common/ActionComponent/ActionPermissionWrapper/__tests__/ActionPermissionWrapper.spec.tsx
@@ -0,0 +1,67 @@
+import React from 'react';
+import { screen } from '@testing-library/react';
+import ActionPermissionWrapper from 'components/common/ActionComponent/ActionPermissionWrapper/ActionPermissionWrapper';
+import { render } from 'lib/testHelpers';
+import { Action, ResourceType } from 'generated-sources';
+import { usePermission } from 'lib/hooks/usePermission';
+import userEvent from '@testing-library/user-event';
+
+jest.mock('lib/hooks/usePermission', () => ({
+ usePermission: jest.fn(),
+}));
+
+const onActionMock = jest.fn();
+
+const testText = 'test';
+const TestComponent = () => {testText}
;
+
+describe('ActionPermissionWrapper', () => {
+ it('children renders', () => {
+ render(
+
+
+
+ );
+ expect(screen.getByText(testText)).toBeInTheDocument();
+ });
+
+ it('action calls when allowed', async () => {
+ (usePermission as jest.Mock).mockImplementation(() => true);
+ render(
+
+
+
+ );
+ await userEvent.click(screen.getByText(testText));
+ expect(onActionMock).toHaveBeenCalledTimes(1);
+ });
+
+ it('action not calls when not allowed', async () => {
+ (usePermission as jest.Mock).mockImplementation(() => false);
+ render(
+
+
+
+ );
+ await userEvent.click(screen.getByText(testText));
+ expect(onActionMock).not.toHaveBeenCalled();
+ });
+});
diff --git a/frontend/src/components/common/ActionComponent/index.ts b/frontend/src/components/common/ActionComponent/index.ts
index d959680b9..707083b6e 100644
--- a/frontend/src/components/common/ActionComponent/index.ts
+++ b/frontend/src/components/common/ActionComponent/index.ts
@@ -3,6 +3,7 @@ import ActionButton from './ActionButton/ActionButton';
import ActionCanButton from './ActionButton/ActionCanButton/ActionCanButton';
import ActionNavLink from './ActionNavLink/ActionNavLink';
import ActionDropdownItem from './ActionDropDownItem/ActionDropdownItem';
+import ActionPermissionWrapper from './ActionPermissionWrapper/ActionPermissionWrapper';
export {
ActionSelect,
@@ -10,4 +11,5 @@ export {
ActionCanButton,
ActionButton,
ActionDropdownItem,
+ ActionPermissionWrapper,
};