Skip to content

Commit 7b9f480

Browse files
committed
Use dynamically loaded Permission description and categories
1 parent 5bc6f3e commit 7b9f480

File tree

8 files changed

+249
-13
lines changed

8 files changed

+249
-13
lines changed

web-ui/src/components/menu/Menu.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ const Root = styled('div')(({theme}) => ({
9696

9797
const adminLinks = [
9898
// ["/admin/permissions", "Permissions"],
99-
["/admin/edit-permissions", "Permissions Roles"],
99+
["/admin/permissions", "Permissions"],
100100
["/admin/roles", "Roles"],
101101
["/admin/users", "Users"],
102102
["/admin/email", "Send Email"],

web-ui/src/components/routes/Routes.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import BirthdayAnniversaryReportPage from "../../pages/BirthdayAnniversaryReport
77
import CheckinsPage from "../../pages/CheckinsPage";
88
import CheckinsReportPage from "../../pages/CheckinsReportPage";
99
import EditSkillsPage from "../../pages/EditSkillsPage";
10-
import EditPermissionsPage from "../../pages/EditPermissionsPage";
10+
import EditPermissionsPage from "../../pages/PermissionsPage";
1111
import GroupIcon from "@mui/icons-material/Group";
1212
import GuildsPage from "../../pages/GuildsPage";
1313
import Header from "../header/Header";
@@ -102,8 +102,8 @@ export default function Routes() {
102102
<Header title="Skills" />
103103
<EditSkillsPage />
104104
</Route>
105-
<Route path="/admin/edit-permissions">
106-
<Header title="Permissions Roles" />
105+
<Route path="/admin/permissions">
106+
<Header title="Permissions" />
107107
<EditPermissionsPage />
108108
</Route>
109109
<Route path="/checkins-reports">

web-ui/src/context/selectors.js

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ export const selectIsAdmin = createSelector(
4141
userProfile && userProfile.role && userProfile.role.includes("ADMIN")
4242
);
4343

44+
export const selectHasPermissionAssignmentPermission = createSelector(
45+
selectUserProfile,
46+
(userProfile) =>
47+
userProfile && userProfile.role && userProfile.permissions.some((p) => p?.permission?.includes("CAN_ASSIGN_ROLE_PERMISSIONS"))
48+
);
49+
4450
export const selectHasReportPermission = createSelector(
4551
selectUserProfile,
4652
(userProfile) =>
@@ -435,15 +441,6 @@ export const selectMyGuilds = createSelector(
435441
)
436442
);
437443

438-
export const selectMyPermissions = createSelector(
439-
selectCurrentUserId,
440-
selectPermissions,
441-
(id, permissions) =>
442-
permissions?.filter((permission) =>
443-
permission.permissions?.some((member) => member.memberId === id)
444-
)
445-
);
446-
447444
export const selectMyTeams = createSelector(
448445
selectCurrentUserId,
449446
selectTeams,
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.permissions-page {
2+
margin: 2rem;
3+
}
4+
5+
.permissions-list {
6+
margin: 1rem;
7+
}
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
import React, { useEffect, useContext, useState } from "react";
2+
3+
import { getPermissionsList } from "../api/permissions";
4+
import {
5+
getRolePermissionsList,
6+
postRolePermissionsList,
7+
deleteRolePermissionsList,
8+
} from "../api/rolepermissions";
9+
import { Checkbox } from "@mui/material";
10+
import { UPDATE_TOAST } from "../context/actions";
11+
import { AppContext } from "../context/AppContext";
12+
import { selectRoles, selectHasPermissionAssignmentPermission } from "../context/selectors";
13+
14+
import "./PermissionsPage.css";
15+
16+
const groupPermissionsByCategory = (permissions) => permissions.reduce((categories, permission) => {
17+
const category = permission.category;
18+
const existingCategory = categories.find(cat => cat.category === category);
19+
20+
// If category exists, add permission to its permissions array
21+
if (existingCategory) {
22+
existingCategory.permissions.push(permission);
23+
} else {
24+
// Create a new category object and add it to categories
25+
categories.push({
26+
category,
27+
permissions: [permission],
28+
});
29+
}
30+
31+
return categories.sort((a,b) => a.category.localeCompare(b.category));
32+
}, []);
33+
34+
const PermissionEditor = ({
35+
permission,
36+
title,
37+
enabled,
38+
onChange
39+
}) => {
40+
return (
41+
<div className="permissions">
42+
<Checkbox
43+
checked={enabled}
44+
id={`permission-field-${permission}`}
45+
onChange={onChange}
46+
inputProps={{ "aria-label": `checkbox ${title}` }}
47+
/>
48+
<label htmlFor={`permission-field-${permission}`}>{title}</label>
49+
</div>
50+
);
51+
};
52+
53+
const isPermissionEnabled = (rolePermissions, permission) => rolePermissions.some((current) => current.id === permission.id);
54+
55+
const EditPermissionsPage = () => {
56+
const { state } = useContext(AppContext);
57+
const { csrf } = state;
58+
const roles = selectRoles(state);
59+
const hasPermission = selectHasPermissionAssignmentPermission(state);
60+
const [selectedRole, setSelectedRole] = useState(roles && roles.find(()=>true));
61+
const [categoriesList, setCategoriesList] = useState([]);
62+
const [rolePermissionsList, setRolePermissionsList] = useState([]);
63+
const [rolePermissions, setRolePermissions] = useState([]);
64+
const [refresh, setRefresh] = useState(true);
65+
66+
useEffect(() => {
67+
const getRolePermissions = async () => {
68+
let res = await getRolePermissionsList(csrf);
69+
let data =
70+
res.payload && res.payload.data && !res.error ? res.payload.data : null;
71+
if (data) {
72+
setRolePermissionsList(data);
73+
}
74+
};
75+
const getPermissions = async () => {
76+
let res = await getPermissionsList(csrf);
77+
let data =
78+
res.payload && res.payload.data && !res.error ? res.payload.data : null;
79+
if (data) {
80+
setCategoriesList(groupPermissionsByCategory(data));
81+
}
82+
};
83+
84+
if (csrf) {
85+
getPermissions();
86+
getRolePermissions();
87+
}
88+
}, [csrf, refresh]);
89+
90+
useEffect(() => {
91+
if(selectedRole && rolePermissionsList) {
92+
const rolePermissions = rolePermissionsList.find((rolePermission) => rolePermission.roleId === selectedRole.id);
93+
rolePermissions && setRolePermissions(rolePermissions?.permissions);
94+
}
95+
96+
}, [selectedRole, rolePermissionsList]);
97+
98+
const handleRoleChange = (event) => {
99+
setSelectedRole(roles.find((role) => role.id === event.target.value));
100+
};
101+
102+
const addRolePermission = async (roleId, permissionId) => {
103+
let newSchema = { roleId: roleId, permissionId: permissionId };
104+
let res = await postRolePermissionsList(newSchema, csrf);
105+
let data =
106+
res.payload && res.payload.data && !res.error ? res.payload.data : null;
107+
if (data) {
108+
window.snackDispatch({
109+
type: UPDATE_TOAST,
110+
payload: {
111+
severity: "success",
112+
toast: `Permission added to Role`,
113+
},
114+
});
115+
} else {
116+
window.snackDispatch({
117+
type: UPDATE_TOAST,
118+
payload: {
119+
severity: "warning",
120+
toast: `Problem changing permission for that role`,
121+
},
122+
});
123+
}
124+
};
125+
126+
const deleteRolePermission = async (roleId, permissionId) => {
127+
let newSchema = { roleId: roleId, permissionId: permissionId };
128+
let res = await deleteRolePermissionsList(newSchema, csrf);
129+
let data = !res.error ? "Success" : null;
130+
if (data) {
131+
window.snackDispatch({
132+
type: UPDATE_TOAST,
133+
payload: {
134+
severity: "success",
135+
toast: `Permission removed from Role`,
136+
},
137+
});
138+
} else {
139+
window.snackDispatch({
140+
type: UPDATE_TOAST,
141+
payload: {
142+
severity: "warning",
143+
toast: `Problem deleting permission for that role`,
144+
},
145+
});
146+
}
147+
};
148+
149+
const handleChange = async (event, roleId, permissionId) => {
150+
if (event?.target?.checked) {
151+
await addRolePermission(roleId, permissionId);
152+
setRefresh(!refresh);
153+
} else {
154+
await deleteRolePermission(roleId, permissionId);
155+
setRefresh(!refresh);
156+
}
157+
};
158+
159+
return (
160+
<div className="permissions-page">
161+
{ hasPermission ?
162+
(
163+
<>
164+
<div>
165+
<label htmlFor="role">Select Role:</label>
166+
<select id="role" value={selectedRole?.id || ''} onChange={handleRoleChange}>
167+
<option value="">-- Please Select --</option>
168+
{roles?.map((role) => (
169+
<option key={role.id} value={role.id}>
170+
{role.role} - {role.description}
171+
</option>
172+
))}
173+
</select>
174+
</div>
175+
176+
{ selectedRole && rolePermissions && categoriesList?.map((category) => (
177+
<div key={category.category} className="permissions-list">
178+
<h3>{category?.category}:</h3>
179+
{ category?.permissions?.map((permission)=> (
180+
<PermissionEditor
181+
key={permission.id}
182+
permission={permission.permission}
183+
title={permission.description}
184+
enabled={isPermissionEnabled(rolePermissions, permission)}
185+
onChange={(event) => handleChange(event, selectedRole?.id, permission.id, csrf)} />
186+
))
187+
}
188+
</div>
189+
))
190+
}
191+
</>
192+
) : (
193+
<h3>You do not have permission to view this page.</h3>
194+
)}
195+
</div>
196+
);
197+
};
198+
199+
export default EditPermissionsPage;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from "react";
2+
import PermissionsPage from "./PermissionsPage";
3+
import { AppContextProvider } from "../context/AppContext";
4+
5+
it("renders correctly", () => {
6+
snapshot(
7+
<AppContextProvider>
8+
<PermissionsPage />
9+
</AppContextProvider>
10+
);
11+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`renders correctly 1`] = `
4+
<div
5+
className="edit-permissions-page"
6+
>
7+
<h3>
8+
You do not have permission to view this page.
9+
</h3>
10+
</div>
11+
`;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`renders correctly 1`] = `
4+
<div
5+
className="permissions-page"
6+
>
7+
<h3>
8+
You do not have permission to view this page.
9+
</h3>
10+
</div>
11+
`;

0 commit comments

Comments
 (0)