update role

main
alex 2023-06-20 16:56:12 +02:00
parent 8429cc10d3
commit 090e50240a
3 changed files with 383 additions and 219 deletions

View File

@ -31,11 +31,8 @@ export default function App() {
setUserSession={setUserSession} setUserSession={setUserSession}
notificationApi={notificationApi} notificationApi={notificationApi}
> >
<SideMenu <SideMenu userSession={userSession} setUserSession={setUserSession} />
userSession={userSession} <PageContent />
setUserSession={setUserSession}
></SideMenu>
<PageContent></PageContent>
</WebSocketProvider> </WebSocketProvider>
</Layout> </Layout>
); );

View File

@ -1,191 +1,34 @@
import { Button, Collapse, Space, Tree } from "antd"; import {
Button,
Collapse,
Input,
Popconfirm,
Space,
Tag,
Tooltip,
Tree,
notification,
} from "antd";
import { import {
Constants, Constants,
SentMessagesCommands, SentMessagesCommands,
WebSocketContext, WebSocketContext,
} from "../../../utils"; } from "../../../utils";
import { EditOutlined, PlusOutlined } from "@ant-design/icons"; import {
import { useContext } from "react"; ArrowDownOutlined,
ArrowUpOutlined,
const treeData = [ CloseOutlined,
{ EditOutlined,
title: "Group Tasks", ExpandAltOutlined,
key: "0-0", PlusOutlined,
children: [ SaveOutlined,
{ } from "@ant-design/icons";
title: "Overview", import { useContext, useState } from "react";
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",
},
],
},
];
export default function AdminAreaRoles() { export default function AdminAreaRoles() {
const webSocketContext = useContext(WebSocketContext); const webSocketContext = useContext(WebSocketContext);
const [notificationApi, notificationContextHolder] =
/* notification.useNotification();
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);
function createTreeDataList(permissions) { function createTreeDataList(permissions) {
const result = []; const result = [];
@ -238,19 +81,256 @@ function Role({ role, rolePermissions }) {
return result; return result;
} }
const onCheck = (checkedKeys, info) => { const onCreateNewRoleClick = () => {
console.log("onCheck", checkedKeys, info); 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 ( return (
<Collapse <Collapse
collapsible="header" collapsible={editMode ? "icon" : "header"}
defaultActiveKey={["2"]} defaultActiveKey={["2"]}
items={[ items={[
{ {
key: "2", 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: ( 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 <h1
style={{ style={{
@ -259,33 +339,46 @@ function Role({ role, rolePermissions }) {
color: Constants.COLORS.PRIMARY, color: Constants.COLORS.PRIMARY,
}} }}
> >
{role.DisplayName} {role.DisplayName}{" "}
{role.Master && <Tag color="purple">Master</Tag>}
</h1> </h1>
<span style={{ margin: 0 }}>{role.Description}</span> <span style={{ margin: 0 }}>{role.Description}</span>
</> </>
)}
</>
), ),
children: ( 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 <Tree
checkable checkable
disabled={role.Master ? true : editMode ? false : true}
selectable={false} selectable={false}
defaultCheckedKeys={rolePermissions} checkedKeys={checkedTreeKeyPermissions}
onCheck={onCheck} onCheck={onTreeCheck}
treeData={createTreeDataList(rolePermissions)} 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}
/>
*/

View File

@ -34,6 +34,9 @@ export const Constants = {
MAX_USERNAME_LENGTH: 20, MAX_USERNAME_LENGTH: 20,
MIN_PASSWORD_LENGTH: 6, MIN_PASSWORD_LENGTH: 6,
MAX_PASSWORD_LENGTH: 64, MAX_PASSWORD_LENGTH: 64,
MIN_ROLE_DISPLAY_NAME: 3,
MAX_ROLE_DISPLAY_NAME: 30,
MAX_ROLE_DESCRIPTION: 80,
}, },
MAX_AVATAR_SIZE: 5 * 1024 * 1024, MAX_AVATAR_SIZE: 5 * 1024 * 1024,
ACCEPTED_FILE_TYPES: ["image/png", "image/jpeg", "image/jpg"], ACCEPTED_FILE_TYPES: ["image/png", "image/jpeg", "image/jpg"],
@ -136,6 +139,7 @@ const ReceivedMessagesCommands = {
TaskUnlocked: 17, TaskUnlocked: 17,
UserProfileUpdated: 18, UserProfileUpdated: 18,
AdminAreaNewRoleCreated: 19, AdminAreaNewRoleCreated: 19,
AdminAreaRoleUpdated: 20,
}; };
// commands sent to the backend server // commands sent to the backend server
@ -147,6 +151,7 @@ export const SentMessagesCommands = {
TaskLocking: 5, TaskLocking: 5,
UpdateUserProfile: 6, UpdateUserProfile: 6,
AdminAreaCreateNewRole: 7, AdminAreaCreateNewRole: 7,
AdminAreaUpdateRole: 8,
}; };
export function WebSocketProvider({ export function WebSocketProvider({
@ -521,10 +526,79 @@ export function WebSocketProvider({
} }
break; break;
case ReceivedMessagesCommands.AdminAreaNewRoleCreated: case ReceivedMessagesCommands.AdminAreaNewRoleCreated:
console.log("body", body);
setAllRoles((arr) => [...arr, body]); setAllRoles((arr) => [...arr, body]);
break; 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: default:
console.error("unknown command", cmd); console.error("unknown command", cmd);