Skip to content

Commit b5c46c8

Browse files
feat(rbac): show warning alert when user is not authorised to create roles (#1064)
1 parent ecec1db commit b5c46c8

File tree

5 files changed

+72
-14
lines changed

5 files changed

+72
-14
lines changed

plugins/rbac/src/components/RbacPage.test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ describe('RbacPage', () => {
3939
data: [],
4040
retry: jest.fn(),
4141
createRoleAllowed: false,
42+
createRoleLoading: false,
4243
});
4344
await renderInTestApp(<RbacPage />);
4445
expect(screen.getByText('Administration')).toBeInTheDocument();

plugins/rbac/src/components/RolesList/RolesList.test.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ describe('RolesList', () => {
6565
data: useRolesMockData,
6666
retry: jest.fn(),
6767
createRoleAllowed: false,
68+
createRoleLoading: false,
6869
});
6970
const { queryByText } = await renderInTestApp(<RolesList />);
7071
expect(queryByText('All roles (2)')).not.toBeNull();
@@ -81,6 +82,7 @@ describe('RolesList', () => {
8182
data: [],
8283
retry: jest.fn(),
8384
createRoleAllowed: false,
85+
createRoleLoading: false,
8486
});
8587
const { getByTestId } = await renderInTestApp(<RolesList />);
8688
expect(getByTestId('roles-table-empty')).not.toBeNull();
@@ -96,6 +98,7 @@ describe('RolesList', () => {
9698
data: useRolesMockData,
9799
retry: jest.fn(),
98100
createRoleAllowed: false,
101+
createRoleLoading: false,
99102
});
100103
const { getAllByTestId, getByText } = await renderInTestApp(<RolesList />);
101104
expect(getAllByTestId('delete-role')).not.toBeNull();
@@ -127,6 +130,7 @@ describe('RolesList', () => {
127130
],
128131
retry: jest.fn(),
129132
createRoleAllowed: false,
133+
createRoleLoading: false,
130134
});
131135
const { getAllByTestId } = await renderInTestApp(<RolesList />);
132136
expect(getAllByTestId('disable-delete-role')).not.toBeNull();
@@ -158,6 +162,7 @@ describe('RolesList', () => {
158162
],
159163
retry: jest.fn(),
160164
createRoleAllowed: true,
165+
createRoleLoading: false,
161166
});
162167
const { getAllByTestId } = await renderInTestApp(<RolesList />);
163168
expect(getAllByTestId('disable-update-role')).not.toBeNull();
@@ -172,6 +177,7 @@ describe('RolesList', () => {
172177
data: useRolesMockData,
173178
retry: jest.fn(),
174179
createRoleAllowed: false,
180+
createRoleLoading: false,
175181
});
176182
const { getByTestId } = await renderInTestApp(<RolesList />);
177183

@@ -188,11 +194,27 @@ describe('RolesList', () => {
188194
data: useRolesMockData,
189195
retry: jest.fn(),
190196
createRoleAllowed: true,
197+
createRoleLoading: false,
191198
});
192199
const { getByTestId } = await renderInTestApp(<RolesList />);
193200

194201
expect(getByTestId('create-role').getAttribute('aria-disabled')).toEqual(
195202
'false',
196203
);
197204
});
205+
206+
it('should show warning alert if user is not authorized to create roles', async () => {
207+
RequirePermissionMock.mockImplementation(props => <>{props.children}</>);
208+
mockUsePermission.mockReturnValue({ loading: false, allowed: true });
209+
mockUseRoles.mockReturnValue({
210+
loading: false,
211+
data: useRolesMockData,
212+
retry: jest.fn(),
213+
createRoleAllowed: false,
214+
createRoleLoading: false,
215+
});
216+
const { getByTestId } = await renderInTestApp(<RolesList />);
217+
218+
expect(getByTestId('create-role-warning')).not.toBeNull();
219+
});
198220
});

plugins/rbac/src/components/RolesList/RolesList.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ export const RolesList = () => {
2727

2828
const [roles, setRoles] = React.useState<number | undefined>();
2929
const classes = useStyles();
30-
const { loading, data, retry, createRoleAllowed } = useRoles();
30+
const { loading, data, retry, createRoleAllowed, createRoleLoading } =
31+
useRoles();
3132

3233
const closeDialog = () => {
3334
setOpenDialog(false);
@@ -44,7 +45,10 @@ export const RolesList = () => {
4445
return (
4546
<>
4647
<SnackbarAlert toastMessage={toastMessage} onAlertClose={onAlertClose} />
47-
<RolesListToolbar createRoleAllowed={createRoleAllowed} />
48+
<RolesListToolbar
49+
createRoleAllowed={createRoleAllowed}
50+
createRoleLoading={createRoleLoading}
51+
/>
4852
<Table
4953
title={
5054
!loading && data?.length

plugins/rbac/src/components/RolesList/RolesListToolbar.tsx

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,57 @@ import React from 'react';
33
import { LinkButton } from '@backstage/core-components';
44

55
import { makeStyles } from '@material-ui/core';
6+
import Alert from '@mui/material/Alert';
7+
import AlertTitle from '@mui/material/AlertTitle';
68

7-
const useStyles = makeStyles(_theme => ({
9+
const useStyles = makeStyles(theme => ({
810
toolbar: {
911
display: 'flex',
1012
justifyContent: 'end',
1113
marginBottom: '24px',
1214
},
15+
rbacPreReqLink: {
16+
color: theme.palette.link,
17+
},
1318
}));
1419

1520
export const RolesListToolbar = ({
1621
createRoleAllowed,
22+
createRoleLoading,
1723
}: {
1824
createRoleAllowed: boolean;
25+
createRoleLoading: boolean;
1926
}) => {
2027
const classes = useStyles();
2128
return (
22-
<span className={classes.toolbar}>
23-
<LinkButton
24-
to="role/new"
25-
color="primary"
26-
variant="contained"
27-
disabled={!createRoleAllowed}
28-
data-testid="create-role"
29-
>
30-
Create
31-
</LinkButton>
32-
</span>
29+
<div>
30+
{!createRoleLoading && !createRoleAllowed && (
31+
<Alert severity="warning" data-testid="create-role-warning">
32+
<AlertTitle>Unable to create role.</AlertTitle>
33+
To enable create role button, the role associacted with your user
34+
should have the permission policies mentioned{' '}
35+
<a
36+
href="https://github.com/janus-idp/backstage-plugins/tree/main/plugins/rbac#prerequisites"
37+
target="blank"
38+
className={classes.rbacPreReqLink}
39+
>
40+
here
41+
</a>{' '}
42+
associated with it.
43+
</Alert>
44+
)}
45+
<br />
46+
<span className={classes.toolbar}>
47+
<LinkButton
48+
to="role/new"
49+
color="primary"
50+
variant="contained"
51+
disabled={!createRoleAllowed}
52+
data-testid="create-role"
53+
>
54+
Create
55+
</LinkButton>
56+
</span>
57+
</div>
3358
);
3459
};

plugins/rbac/src/hooks/useRoles.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export const useRoles = (
2222
): {
2323
loading: boolean;
2424
data: RolesData[];
25+
createRoleLoading: boolean;
2526
createRoleAllowed: boolean;
2627
retry: () => void;
2728
} => {
@@ -52,6 +53,10 @@ export const useRoles = (
5253
resourceRef: catalogEntityReadPermission.resourceType,
5354
});
5455

56+
const createRoleLoading =
57+
policyEntityCreatePermissionResult.loading ||
58+
catalogEntityReadPermissionResult.loading;
59+
5560
const createRoleAllowed =
5661
policyEntityCreatePermissionResult.allowed &&
5762
catalogEntityReadPermissionResult.allowed;
@@ -113,6 +118,7 @@ export const useRoles = (
113118
return {
114119
loading,
115120
data,
121+
createRoleLoading,
116122
createRoleAllowed,
117123
retry: roleRetry,
118124
};

0 commit comments

Comments
 (0)