update role
parent
8429cc10d3
commit
090e50240a
|
@ -31,11 +31,8 @@ export default function App() {
|
|||
setUserSession={setUserSession}
|
||||
notificationApi={notificationApi}
|
||||
>
|
||||
<SideMenu
|
||||
userSession={userSession}
|
||||
setUserSession={setUserSession}
|
||||
></SideMenu>
|
||||
<PageContent></PageContent>
|
||||
<SideMenu userSession={userSession} setUserSession={setUserSession} />
|
||||
<PageContent />
|
||||
</WebSocketProvider>
|
||||
</Layout>
|
||||
);
|
||||
|
|
|
@ -1,191 +1,34 @@
|
|||
import { Button, Collapse, Space, Tree } from "antd";
|
||||
import {
|
||||
Button,
|
||||
Collapse,
|
||||
Input,
|
||||
Popconfirm,
|
||||
Space,
|
||||
Tag,
|
||||
Tooltip,
|
||||
Tree,
|
||||
notification,
|
||||
} from "antd";
|
||||
import {
|
||||
Constants,
|
||||
SentMessagesCommands,
|
||||
WebSocketContext,
|
||||
} from "../../../utils";
|
||||
import { EditOutlined, PlusOutlined } from "@ant-design/icons";
|
||||
import { useContext } from "react";
|
||||
|
||||
const treeData = [
|
||||
{
|
||||
title: "Group Tasks",
|
||||
key: "0-0",
|
||||
children: [
|
||||
{
|
||||
title: "Overview",
|
||||
key: "0-0-0",
|
||||
children: [
|
||||
{
|
||||
title: "Janex",
|
||||
key: "0-0-0-0",
|
||||
children: [
|
||||
{
|
||||
title: "Start new task",
|
||||
key: "0-0-0-0-0",
|
||||
},
|
||||
{
|
||||
title: "Reload group task config",
|
||||
key: "0-0-0-0-1",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Roese",
|
||||
key: "0-0-0-1",
|
||||
children: [
|
||||
{
|
||||
title: "Start new task",
|
||||
key: "0-0-0-1-0",
|
||||
},
|
||||
{
|
||||
title: "Reload group task config",
|
||||
key: "0-0-0-1-1",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Test",
|
||||
key: "0-0-0-2",
|
||||
children: [
|
||||
{
|
||||
title: "Start new task",
|
||||
key: "0-0-0-2-0",
|
||||
},
|
||||
{
|
||||
title: "Reload group task config",
|
||||
key: "0-0-0-2-1",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Umbach",
|
||||
key: "0-0-0-3",
|
||||
children: [
|
||||
{
|
||||
title: "Start new task",
|
||||
key: "0-0-0-3-0",
|
||||
},
|
||||
{
|
||||
title: "Reload group task config",
|
||||
key: "0-0-0-3-1",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "History",
|
||||
key: "0-0-1",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Admin Area",
|
||||
key: "2-1",
|
||||
children: [
|
||||
{
|
||||
title: "Roles",
|
||||
key: "0-1-0",
|
||||
children: [
|
||||
{
|
||||
title: "Add role",
|
||||
key: "0-1-0-0",
|
||||
},
|
||||
{
|
||||
title: "Update role",
|
||||
key: "0-1-0-1",
|
||||
},
|
||||
{
|
||||
title: "Delete role",
|
||||
key: "0-1-0-2",
|
||||
},
|
||||
{
|
||||
title: "Add user to role",
|
||||
key: "0-1-0-3",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Logs",
|
||||
key: "0-1-1",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
import {
|
||||
ArrowDownOutlined,
|
||||
ArrowUpOutlined,
|
||||
CloseOutlined,
|
||||
EditOutlined,
|
||||
ExpandAltOutlined,
|
||||
PlusOutlined,
|
||||
SaveOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { useContext, useState } from "react";
|
||||
|
||||
export default function AdminAreaRoles() {
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
|
||||
/*
|
||||
const onSelect = (selectedKeys, info) => {
|
||||
console.log("selected", selectedKeys, info);
|
||||
};
|
||||
const onCheck = (checkedKeys, info) => {
|
||||
console.log("onCheck", checkedKeys, info);
|
||||
}; */
|
||||
|
||||
/*
|
||||
rolePermissions={
|
||||
webSocketContext.AdminAreaRolesPermissions.find(
|
||||
(r) => r.RoleId === role.Id
|
||||
).Permissions
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
const onCreateNewRoleClick = () => {
|
||||
webSocketContext.SendSocketMessage(
|
||||
SentMessagesCommands.AdminAreaCreateNewRole,
|
||||
{}
|
||||
);
|
||||
};
|
||||
|
||||
const getRolePermissions = (role) => {
|
||||
const rolePermissions = webSocketContext.AdminAreaRolesPermissions.find(
|
||||
(r) => r.RoleId === role.Id
|
||||
);
|
||||
|
||||
if (rolePermissions === undefined) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return rolePermissions.Permissions;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Space direction="vertical" style={{ width: "100%" }}>
|
||||
{webSocketContext.AllRoles.map((role) => (
|
||||
<Role
|
||||
key={role.Id}
|
||||
role={role}
|
||||
rolePermissions={getRolePermissions(role)}
|
||||
/>
|
||||
))}
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
shape="round"
|
||||
icon={<PlusOutlined />}
|
||||
size="large"
|
||||
onClick={() => onCreateNewRoleClick()}
|
||||
>
|
||||
Create new role
|
||||
</Button>
|
||||
</div>
|
||||
</Space>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Role({ role, rolePermissions }) {
|
||||
console.warn("role", rolePermissions);
|
||||
const [notificationApi, notificationContextHolder] =
|
||||
notification.useNotification();
|
||||
|
||||
function createTreeDataList(permissions) {
|
||||
const result = [];
|
||||
|
@ -238,19 +81,256 @@ function Role({ role, rolePermissions }) {
|
|||
return result;
|
||||
}
|
||||
|
||||
const onCheck = (checkedKeys, info) => {
|
||||
console.log("onCheck", checkedKeys, info);
|
||||
const onCreateNewRoleClick = () => {
|
||||
webSocketContext.SendSocketMessage(
|
||||
SentMessagesCommands.AdminAreaCreateNewRole,
|
||||
{}
|
||||
);
|
||||
};
|
||||
|
||||
const getRolePermissions = (role) => {
|
||||
const rolePermissions = webSocketContext.AdminAreaRolesPermissions.find(
|
||||
(r) => r.RoleId === role.Id
|
||||
);
|
||||
|
||||
console.warn("getRolePermissions", rolePermissions);
|
||||
|
||||
if (rolePermissions === undefined || rolePermissions.Permissions === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return rolePermissions.Permissions;
|
||||
};
|
||||
|
||||
const treeData = createTreeDataList(
|
||||
getRolePermissions(
|
||||
webSocketContext.AllRoles.find((role) => role.Master === true)
|
||||
)
|
||||
);
|
||||
|
||||
return (
|
||||
<Space direction="vertical" style={{ width: "100%" }}>
|
||||
{notificationContextHolder}
|
||||
{webSocketContext.AllRoles.map((role) => (
|
||||
<Role
|
||||
key={role.Id}
|
||||
treeData={treeData}
|
||||
role={role}
|
||||
webSocketContext={webSocketContext}
|
||||
notificationApi={notificationApi}
|
||||
/>
|
||||
))}
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<Popconfirm
|
||||
placement="top"
|
||||
okText="Create"
|
||||
title="Are you sure you want to create a new role?"
|
||||
onConfirm={() => onCreateNewRoleClick()}
|
||||
>
|
||||
<Button shape="round" icon={<PlusOutlined />} size="large">
|
||||
Create new role
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
|
||||
function Role({ treeData, role, webSocketContext, notificationApi }) {
|
||||
const [editMode, setEditMode] = useState(false);
|
||||
const [roleDisplayName, setRoleDisplayName] = useState(role.DisplayName);
|
||||
const [roleDescription, setRoleDescription] = useState(role.Description);
|
||||
|
||||
const getRolePermissions = (role) => {
|
||||
const rolePermissions = webSocketContext.AdminAreaRolesPermissions.find(
|
||||
(r) => r.RoleId === role.Id
|
||||
);
|
||||
|
||||
if (rolePermissions === undefined || rolePermissions.Permissions === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return rolePermissions.Permissions;
|
||||
};
|
||||
|
||||
const rolePermissions = getRolePermissions(role);
|
||||
|
||||
const [checkedTreeKeyPermissions, setCheckedTreeKeyPermissions] =
|
||||
useState(rolePermissions);
|
||||
|
||||
const onTreeCheck = (checkedKeys, info) =>
|
||||
setCheckedTreeKeyPermissions(checkedKeys);
|
||||
|
||||
const getMasterPermissions = () => {
|
||||
return webSocketContext.AdminAreaRolesPermissions.find(
|
||||
(role) =>
|
||||
role.RoleId ===
|
||||
webSocketContext.AllRoles.find((role) => role.Master === true).Id
|
||||
).Permissions;
|
||||
};
|
||||
|
||||
const getTreePermissionsChanges = () => {
|
||||
const masterPermissions = getMasterPermissions();
|
||||
|
||||
// the checkedKeys permissions must be filtered out, because permissions like admin_area.roles are specified in keys, but are not a permission, but only the children of it admin_area.roles.add_role
|
||||
const potentialPermissions = checkedTreeKeyPermissions.filter(
|
||||
(permission) =>
|
||||
masterPermissions.find((mPermission) => mPermission === permission)
|
||||
);
|
||||
|
||||
const addedPermissions = potentialPermissions.filter(
|
||||
(permission) => !rolePermissions.includes(permission)
|
||||
);
|
||||
|
||||
const removedPermissions = rolePermissions.filter(
|
||||
(permission) => !potentialPermissions.includes(permission)
|
||||
);
|
||||
|
||||
return {
|
||||
addedPermissions,
|
||||
removedPermissions,
|
||||
};
|
||||
};
|
||||
|
||||
const onEditClick = () => {
|
||||
setCheckedTreeKeyPermissions(rolePermissions);
|
||||
setEditMode(true);
|
||||
};
|
||||
|
||||
const onSaveClick = () => {
|
||||
let changes = {};
|
||||
|
||||
const permissionChanges = getTreePermissionsChanges();
|
||||
|
||||
if (roleDisplayName !== role.DisplayName) {
|
||||
changes["DisplayName"] = roleDisplayName;
|
||||
}
|
||||
if (roleDescription !== role.Description) {
|
||||
changes["Description"] = roleDescription;
|
||||
}
|
||||
if (permissionChanges.addedPermissions.length > 0) {
|
||||
changes["AddedPermissions"] = permissionChanges.addedPermissions;
|
||||
}
|
||||
if (permissionChanges.removedPermissions.length > 0) {
|
||||
changes["RemovedPermissions"] = permissionChanges.removedPermissions;
|
||||
}
|
||||
|
||||
// user has clicked on save icon but has nothing changed
|
||||
if (
|
||||
changes.DisplayName === undefined &&
|
||||
changes.Description === undefined &&
|
||||
permissionChanges.addedPermissions.length === 0 &&
|
||||
permissionChanges.removedPermissions.length === 0
|
||||
) {
|
||||
setEditMode(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (changes.DisplayName !== undefined) {
|
||||
if (
|
||||
changes.DisplayName.length < Constants.GLOBALS.MIN_ROLE_DISPLAY_NAME
|
||||
) {
|
||||
notificationApi["error"]({
|
||||
message: `Display name must be greater than ${Constants.GLOBALS.MIN_ROLE_DISPLAY_NAME}`,
|
||||
description: `Please enter a longer display name`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (
|
||||
changes.DisplayName.length > Constants.GLOBALS.MAX_ROLE_DISPLAY_NAME
|
||||
) {
|
||||
notificationApi["error"]({
|
||||
message: `Display name must be less than ${Constants.GLOBALS.MAX_ROLE_DISPLAY_NAME}`,
|
||||
description: `Please enter a shorter display name`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
changes.Description !== undefined &&
|
||||
changes.Description.length > Constants.GLOBALS.MAX_ROLE_DESCRIPTION
|
||||
) {
|
||||
notificationApi["error"]({
|
||||
message: `Description must be less than ${Constants.GLOBALS.MAX_ROLE_DESCRIPTION}`,
|
||||
description: `Please enter a shorter description`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setEditMode(false);
|
||||
|
||||
webSocketContext.SendSocketMessage(
|
||||
SentMessagesCommands.AdminAreaUpdateRole,
|
||||
{
|
||||
RoleId: role.Id,
|
||||
Changes: changes,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const onCloseClick = () => {
|
||||
setEditMode(false);
|
||||
|
||||
setRoleDisplayName(role.DisplayName);
|
||||
setRoleDescription(role.Description);
|
||||
};
|
||||
|
||||
return (
|
||||
<Collapse
|
||||
collapsible="header"
|
||||
collapsible={editMode ? "icon" : "header"}
|
||||
defaultActiveKey={["2"]}
|
||||
items={[
|
||||
{
|
||||
key: "2",
|
||||
extra: <EditOutlined />,
|
||||
extra: editMode ? (
|
||||
<Space style={{ paddingLeft: 10 }} size="small">
|
||||
<Tooltip title="Move role up">
|
||||
<ArrowUpOutlined />
|
||||
</Tooltip>
|
||||
<Tooltip title="Move role down">
|
||||
<ArrowDownOutlined />
|
||||
</Tooltip>
|
||||
<Tooltip title="Save">
|
||||
<SaveOutlined onClick={() => onSaveClick()} />
|
||||
</Tooltip>
|
||||
<Tooltip title="Close">
|
||||
<CloseOutlined onClick={() => onCloseClick()} />
|
||||
</Tooltip>
|
||||
</Space>
|
||||
) : (
|
||||
<Tooltip title="Edit">
|
||||
<EditOutlined onClick={() => onEditClick()} />
|
||||
</Tooltip>
|
||||
),
|
||||
label: (
|
||||
<>
|
||||
{editMode ? (
|
||||
<>
|
||||
<Input
|
||||
style={{
|
||||
fontWeight: "bold",
|
||||
color: Constants.COLORS.PRIMARY,
|
||||
}}
|
||||
value={roleDisplayName}
|
||||
onChange={(e) => setRoleDisplayName(e.target.value)}
|
||||
minLength={Constants.GLOBALS.MIN_ROLE_DISPLAY_NAME}
|
||||
maxLength={Constants.GLOBALS.MAX_ROLE_DISPLAY_NAME}
|
||||
/>
|
||||
|
||||
<Input
|
||||
value={roleDescription}
|
||||
onChange={(e) => setRoleDescription(e.target.value)}
|
||||
maxLength={Constants.GLOBALS.MAX_ROLE_DESCRIPTION}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<h1
|
||||
style={{
|
||||
|
@ -259,33 +339,46 @@ function Role({ role, rolePermissions }) {
|
|||
color: Constants.COLORS.PRIMARY,
|
||||
}}
|
||||
>
|
||||
{role.DisplayName}
|
||||
{role.DisplayName}{" "}
|
||||
{role.Master && <Tag color="purple">Master</Tag>}
|
||||
</h1>
|
||||
|
||||
<span style={{ margin: 0 }}>{role.Description}</span>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
children: (
|
||||
<>
|
||||
{role.Master && editMode && (
|
||||
<p style={{ fontStyle: "italic" }}>
|
||||
Rights cannot be edited, because this role is the master and
|
||||
has all rights.
|
||||
</p>
|
||||
)}
|
||||
|
||||
{editMode ? (
|
||||
<Tree
|
||||
checkable
|
||||
disabled={role.Master ? true : editMode ? false : true}
|
||||
selectable={false}
|
||||
defaultCheckedKeys={rolePermissions}
|
||||
onCheck={onCheck}
|
||||
treeData={createTreeDataList(rolePermissions)}
|
||||
checkedKeys={checkedTreeKeyPermissions}
|
||||
onCheck={onTreeCheck}
|
||||
treeData={treeData}
|
||||
/>
|
||||
) : (
|
||||
<Tree
|
||||
checkable
|
||||
disabled={true}
|
||||
selectable={false}
|
||||
checkedKeys={rolePermissions}
|
||||
treeData={treeData}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
<Tree
|
||||
checkable
|
||||
defaultExpandedKeys={["0-0"]}
|
||||
defaultCheckedKeys={["0-0", "0-1-0-0", "0-1-0-1", "0-1-0-3"]}
|
||||
treeData={createListFromArgument(rolePermissions)}
|
||||
onSelect={onSelect}
|
||||
onCheck={onCheck}
|
||||
/>
|
||||
*/
|
||||
|
|
78
src/utils.js
78
src/utils.js
|
@ -34,6 +34,9 @@ export const Constants = {
|
|||
MAX_USERNAME_LENGTH: 20,
|
||||
MIN_PASSWORD_LENGTH: 6,
|
||||
MAX_PASSWORD_LENGTH: 64,
|
||||
MIN_ROLE_DISPLAY_NAME: 3,
|
||||
MAX_ROLE_DISPLAY_NAME: 30,
|
||||
MAX_ROLE_DESCRIPTION: 80,
|
||||
},
|
||||
MAX_AVATAR_SIZE: 5 * 1024 * 1024,
|
||||
ACCEPTED_FILE_TYPES: ["image/png", "image/jpeg", "image/jpg"],
|
||||
|
@ -136,6 +139,7 @@ const ReceivedMessagesCommands = {
|
|||
TaskUnlocked: 17,
|
||||
UserProfileUpdated: 18,
|
||||
AdminAreaNewRoleCreated: 19,
|
||||
AdminAreaRoleUpdated: 20,
|
||||
};
|
||||
|
||||
// commands sent to the backend server
|
||||
|
@ -147,6 +151,7 @@ export const SentMessagesCommands = {
|
|||
TaskLocking: 5,
|
||||
UpdateUserProfile: 6,
|
||||
AdminAreaCreateNewRole: 7,
|
||||
AdminAreaUpdateRole: 8,
|
||||
};
|
||||
|
||||
export function WebSocketProvider({
|
||||
|
@ -521,10 +526,79 @@ export function WebSocketProvider({
|
|||
}
|
||||
break;
|
||||
case ReceivedMessagesCommands.AdminAreaNewRoleCreated:
|
||||
console.log("body", body);
|
||||
|
||||
setAllRoles((arr) => [...arr, body]);
|
||||
break;
|
||||
case ReceivedMessagesCommands.AdminAreaRoleUpdated:
|
||||
setAllRoles((arr) => {
|
||||
const newArr = [...arr];
|
||||
|
||||
const arrIndex = arr.findIndex((arr1) => arr1.Id === body.RoleId);
|
||||
|
||||
if (body.Changes.DisplayName !== undefined) {
|
||||
newArr[arrIndex].DisplayName = body.Changes.DisplayName;
|
||||
}
|
||||
|
||||
if (body.Changes.Description !== undefined) {
|
||||
newArr[arrIndex].Description = body.Changes.Description;
|
||||
}
|
||||
|
||||
return newArr;
|
||||
});
|
||||
|
||||
if (
|
||||
body.Changes.AddedPermissions !== undefined ||
|
||||
body.Changes.RemovedPermissions !== undefined
|
||||
) {
|
||||
setAdminAreaRolesPermissions((arr) => {
|
||||
const newArr = [...arr];
|
||||
|
||||
const roleIndex = arr.findIndex(
|
||||
(item) => item.RoleId === body.RoleId
|
||||
);
|
||||
|
||||
console.log("roleIndex", roleIndex);
|
||||
|
||||
if (body.Changes.AddedPermissions !== undefined) {
|
||||
console.log("updating role", newArr[roleIndex].Permissions);
|
||||
|
||||
if (newArr[roleIndex].Permissions === null) {
|
||||
console.log("here null");
|
||||
newArr[roleIndex].Permissions = body.Changes.AddedPermissions;
|
||||
} else {
|
||||
console.warn("here2");
|
||||
newArr[roleIndex].Permissions = newArr[
|
||||
roleIndex
|
||||
].Permissions.concat(body.Changes.AddedPermissions);
|
||||
}
|
||||
}
|
||||
|
||||
if (body.Changes.RemovedPermissions !== undefined) {
|
||||
newArr[roleIndex].Permissions = newArr[
|
||||
roleIndex
|
||||
].Permissions.filter(
|
||||
(permission) =>
|
||||
!body.Changes.RemovedPermissions.includes(permission)
|
||||
);
|
||||
}
|
||||
|
||||
console.log("after edit", newArr[roleIndex].Permissions);
|
||||
|
||||
return newArr;
|
||||
});
|
||||
}
|
||||
|
||||
if (body.Result !== undefined) {
|
||||
if (body.Result.DisplayName !== undefined) {
|
||||
if (body.Result.DisplayName === 1) {
|
||||
notificationApi["error"]({
|
||||
message: `Display name could be changed`,
|
||||
description: `Display name already in use`,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error("unknown command", cmd);
|
||||
|
|
Loading…
Reference in New Issue