Skip to content

Commit 2e04ccb

Browse files
authored
fix(rbac): alert display issue after role creating/updating (#1354)
Signed-off-by: Yi Cai <[email protected]>
1 parent 83fae1a commit 2e04ccb

File tree

7 files changed

+74
-13
lines changed

7 files changed

+74
-13
lines changed

packages/backend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
"@backstage/plugin-search-backend-module-pg": "^0.5.22",
3939
"@backstage/plugin-search-backend-node": "^1.2.17",
4040
"@backstage/plugin-techdocs-backend": "^1.9.6",
41-
"@janus-idp/backstage-plugin-rbac-backend": "^2.2.4",
41+
"@janus-idp/backstage-plugin-rbac-backend": "^2.4.1",
4242
"@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "^0.1.10",
4343
"@backstage/plugin-search-backend-module-catalog": "^0.1.17",
4444
"@backstage/plugin-search-backend-module-techdocs": "^0.1.17",

plugins/rbac/src/components/CreateRole/RoleForm.tsx

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import {
2828
isSamePermissionPolicy,
2929
onlyInLeft,
3030
} from '../../utils/rbac-utils';
31-
import { useToast } from '../ToastContext';
3231
import { AddedMembersTable } from './AddedMembersTable';
3332
import { AddMembersForm } from './AddMembersForm';
3433
import { PermissionPoliciesForm } from './PermissionPoliciesForm';
@@ -58,18 +57,19 @@ export const RoleForm = ({
5857
submitLabel,
5958
initialValues,
6059
}: RoleFormProps) => {
61-
const { setToastMessage } = useToast();
6260
const [activeStep, setActiveStep] = React.useState<number>(step || 0);
6361
const navigate = useNavigate();
6462
const rbacApi = useApi(rbacApiRef);
6563

66-
const navigateTo = () => {
64+
const navigateTo = (action?: string) => {
65+
const stateProp = action
66+
? { state: { toastMessage: `Role ${action} successfully` } }
67+
: { state: { toastMessage: '' } };
6768
if (step && roleName) {
6869
const { kind, namespace, name } = getKindNamespaceName(roleName);
69-
70-
navigate(`../roles/${kind}/${namespace}/${name}`);
70+
navigate(`../roles/${kind}/${namespace}/${name}`, stateProp);
7171
} else {
72-
navigate('..');
72+
navigate('..', stateProp);
7373
}
7474
};
7575

@@ -125,8 +125,7 @@ export const RoleForm = ({
125125
);
126126
}
127127
}
128-
setToastMessage(`Role ${name} updated successfully`);
129-
navigateTo();
128+
navigateTo(`${name} updated`);
130129
}
131130
} catch (e) {
132131
formikHelpers.setStatus({ submitError: e });
@@ -156,8 +155,7 @@ export const RoleForm = ({
156155
}`,
157156
);
158157
}
159-
setToastMessage(`Role ${newData.name} created successfully`);
160-
navigateTo();
158+
navigateTo(`${newData.name} created`);
161159
} catch (e) {
162160
formikHelpers.setStatus({ submitError: e });
163161
}

plugins/rbac/src/components/RoleOverview/RoleOverviewPage.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Header, Page, TabbedLayout } from '@backstage/core-components';
55

66
import { Grid } from '@material-ui/core';
77

8+
import { useLocationToast } from '../../hooks/useLocationToast';
89
import { SnackbarAlert } from '../SnackbarAlert';
910
import { useToast } from '../ToastContext';
1011
import { AboutCard } from './AboutCard';
@@ -15,6 +16,8 @@ export const RoleOverviewPage = () => {
1516
const { roleName, roleNamespace, roleKind } = useParams();
1617
const { toastMessage, setToastMessage } = useToast();
1718

19+
useLocationToast(setToastMessage);
20+
1821
const onAlertClose = () => {
1922
setToastMessage('');
2023
};

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Table, WarningPanel } from '@backstage/core-components';
44

55
import { makeStyles } from '@material-ui/core';
66

7+
import { useLocationToast } from '../../hooks/useLocationToast';
78
import { useRoles } from '../../hooks/useRoles';
89
import { RolesData } from '../../types';
910
import { SnackbarAlert } from '../SnackbarAlert';
@@ -24,7 +25,7 @@ const useStyles = makeStyles(theme => ({
2425
export const RolesList = () => {
2526
const { toastMessage, setToastMessage } = useToast();
2627
const { openDialog, setOpenDialog, deleteRoleName } = useDeleteDialog();
27-
28+
useLocationToast(setToastMessage);
2829
const [roles, setRoles] = React.useState<number | undefined>();
2930
const classes = useStyles();
3031
const { loading, data, retry, createRoleAllowed, createRoleLoading, error } =
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { useLocation } from 'react-router-dom';
2+
3+
import { renderHook } from '@testing-library/react-hooks';
4+
5+
import { useLocationToast } from './useLocationToast';
6+
7+
jest.mock('react-router-dom', () => ({
8+
useLocation: jest.fn(),
9+
}));
10+
11+
describe('useLocationToast', () => {
12+
it('sets toast message based on location state', () => {
13+
const mockSetToastMessage = jest.fn();
14+
15+
(useLocation as jest.Mock).mockReturnValue({
16+
state: { toastMessage: 'Success Message' },
17+
});
18+
19+
renderHook(() => useLocationToast(mockSetToastMessage));
20+
21+
expect(mockSetToastMessage).toHaveBeenCalledWith('Success Message');
22+
});
23+
24+
it('cleans up by setting toast message to an empty string', () => {
25+
const mockSetToastMessage = jest.fn();
26+
27+
(useLocation as jest.Mock).mockReturnValue({
28+
state: { toastMessage: 'Success Message' },
29+
});
30+
31+
const { unmount } = renderHook(() => useLocationToast(mockSetToastMessage));
32+
unmount();
33+
34+
expect(mockSetToastMessage).toHaveBeenCalledWith('');
35+
});
36+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { useEffect } from 'react';
2+
import { useLocation } from 'react-router-dom';
3+
4+
export const useLocationToast = (
5+
setToastMessage: (message: string) => void,
6+
) => {
7+
const location = useLocation();
8+
9+
useEffect(() => {
10+
if (location?.state?.toastMessage) {
11+
setToastMessage(location.state.toastMessage);
12+
}
13+
return () => setToastMessage('');
14+
}, [location, setToastMessage]);
15+
};

plugins/rbac/tests/rbac.spec.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ test.describe('RBAC plugin', () => {
108108
});
109109
await page
110110
.getByPlaceholder('Search by user name or group name')
111-
.fill('Guest Use');
111+
.fill('Guest User');
112112
await page.getByText('Guest User').click();
113113
await expect(
114114
page.getByRole('heading', {
@@ -122,6 +122,14 @@ test.describe('RBAC plugin', () => {
122122
await clickButton('Save', page);
123123
await verifyText('Role role:default/rbac_admin updated successfully', page);
124124

125+
// alert doesn't show up after Cancel button is clicked
126+
await page.locator(RoleOverviewPO.updateMembers).click();
127+
await expect(page.getByRole('heading', { name: 'Edit Role' })).toBeVisible({
128+
timeout: 20000,
129+
});
130+
await clickButton('Cancel', page);
131+
await expect(page.getByRole('alert')).toHaveCount(0);
132+
125133
// edit/update policies
126134
await page.locator(RoleOverviewPO.updatePolicies).click();
127135
await expect(page.getByRole('heading', { name: 'Edit Role' })).toBeVisible({

0 commit comments

Comments
 (0)