added multiple contexts
parent
c125751f17
commit
ba5d3e9d20
52
src/App.js
52
src/App.js
|
@ -2,11 +2,52 @@ import { useState } from "react";
|
|||
import "antd/dist/reset.css";
|
||||
import "./App.css";
|
||||
import Login from "./Pages/Login";
|
||||
import { Layout, message, notification } from "antd";
|
||||
import { UseUserSession, WebSocketProvider } from "./utils";
|
||||
import { Layout, notification } from "antd";
|
||||
import { UseUserSession } from "./utils";
|
||||
import DashboardLayout from "./Components/DashboardLayout";
|
||||
import WebSocketProvider from "./Contexts/WebSocketContext";
|
||||
import SideBarProvider from "./Contexts/SideBarContext";
|
||||
import { AppProvider } from "./Contexts/AppContext";
|
||||
|
||||
export default function App() {
|
||||
const { userSession, setUserSession } = UseUserSession();
|
||||
const [isWebSocketReady, setIsWebSocketReady] = useState(true);
|
||||
|
||||
if (!userSession) {
|
||||
return <Login />;
|
||||
}
|
||||
|
||||
console.info(
|
||||
"\n %c Admin Dashboard %c v0.1.0 %c \n",
|
||||
"background-color: #555;color: #fff;padding: 3px 2px 3px 3px;border-radius: 3px 0 0 3px;font-family: DejaVu Sans,Verdana,Geneva,sans-serif;text-shadow: 0 1px 0 rgba(1, 1, 1, 0.3)",
|
||||
"background-color: #bc81e0;background-image: linear-gradient(90deg, #e67e22, #9b59b6);color: #fff;padding: 3px 3px 3px 2px;border-radius: 0 3px 3px 0;font-family: DejaVu Sans,Verdana,Geneva,sans-serif;text-shadow: 0 1px 0 rgba(1, 1, 1, 0.3)",
|
||||
"background-color: transparent"
|
||||
);
|
||||
|
||||
return (
|
||||
<Layout style={{ minHeight: "100vh" }}>
|
||||
<AppProvider>
|
||||
<SideBarProvider>
|
||||
<WebSocketProvider
|
||||
userSession={userSession}
|
||||
setUserSession={setUserSession}
|
||||
isWebSocketReady={isWebSocketReady}
|
||||
setIsWebSocketReady={setIsWebSocketReady}
|
||||
>
|
||||
<ReconnectingView isWebSocketReady={isWebSocketReady} />
|
||||
|
||||
<DashboardLayout
|
||||
userSession={userSession}
|
||||
setUserSession={setUserSession}
|
||||
/>
|
||||
</WebSocketProvider>
|
||||
</SideBarProvider>
|
||||
</AppProvider>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
/*export default function App() {
|
||||
const [notificationApi, notificationContextHolder] =
|
||||
notification.useNotification();
|
||||
const { userSession, setUserSession } = UseUserSession();
|
||||
|
@ -26,6 +67,7 @@ export default function App() {
|
|||
return (
|
||||
<Layout style={{ minHeight: "100vh" }}>
|
||||
{notificationContextHolder}
|
||||
|
||||
<WebSocketProvider
|
||||
userSession={userSession}
|
||||
setUserSession={setUserSession}
|
||||
|
@ -42,9 +84,9 @@ export default function App() {
|
|||
</WebSocketProvider>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
} */
|
||||
|
||||
const ReconnectingView = ({ webSocketIsReady }) => {
|
||||
const ReconnectingView = ({ isWebSocketReady }) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
|
@ -54,7 +96,7 @@ const ReconnectingView = ({ webSocketIsReady }) => {
|
|||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: "rgba(0, 0, 0, 0.8)",
|
||||
display: webSocketIsReady ? "none" : "block",
|
||||
display: isWebSocketReady ? "none" : "block",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
zIndex: 9999,
|
||||
|
|
|
@ -11,11 +11,12 @@ import Scanners from "../../Pages/Scanners";
|
|||
import AdminAreaRoles from "../../Pages/AdminArea/Roles";
|
||||
import AdminAreaLogs from "../../Pages/AdminArea/Logs";
|
||||
import AllUsers from "../../Pages/AllUsers";
|
||||
import { useContext } from "react";
|
||||
import GroupTasks from "../../Pages/GroupTasks/Overview";
|
||||
import GroupTasksHistory from "../../Pages/GroupTasks/History";
|
||||
import PageNotFound from "../../Pages/PageNotFound";
|
||||
import EquipmentDocumentationOverview from "../../Pages/EquipmentDocumentation";
|
||||
import { UserProfileProvider } from "../../Contexts/UserProfileContext";
|
||||
import { UsersProvider } from "../../Contexts/UsersContext";
|
||||
|
||||
export default function AppRoutes() {
|
||||
// const webSocketContext = useContext(WebSocketContext);
|
||||
|
@ -79,9 +80,23 @@ export default function AppRoutes() {
|
|||
|
||||
<Route path="/scanners" element={<Scanners />} />
|
||||
|
||||
<Route path="/users" element={<AllUsers />} />
|
||||
<Route
|
||||
path="/users"
|
||||
element={
|
||||
<UsersProvider>
|
||||
<AllUsers />
|
||||
</UsersProvider>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route path="/user-profile" element={<UserProfile />} />
|
||||
<Route
|
||||
path="/user-profile"
|
||||
element={
|
||||
<UserProfileProvider>
|
||||
<UserProfile />
|
||||
</UserProfileProvider>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route path="/admin-area/roles" element={<AdminAreaRoles />} />
|
||||
|
||||
|
|
|
@ -58,3 +58,16 @@ export function MyAvatar({
|
|||
|
||||
return <MyAvat />;
|
||||
}
|
||||
|
||||
export function MyUserAvatar({ avatar, size = "default" }) {
|
||||
if (avatar === "") {
|
||||
return <Avatar icon={<UserOutlined />} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Avatar
|
||||
src={Constants.STATIC_CONTENT_ADDRESS + "avatars/" + avatar}
|
||||
size={size}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { EditOutlined } from "@ant-design/icons";
|
||||
import { Input, Typography } from "antd";
|
||||
import { useState } from "react";
|
||||
import { Constants } from "../../utils";
|
||||
|
||||
export default function MyTypography({ value, setValue, maxLength }) {
|
||||
const [editing, setEditing] = useState(false);
|
||||
|
|
|
@ -14,15 +14,11 @@ import Sider from "antd/es/layout/Sider";
|
|||
import { useContext, useEffect, useState } from "react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import PropTypes from "prop-types";
|
||||
import {
|
||||
Constants,
|
||||
WebSocketContext,
|
||||
getUserId,
|
||||
hasOnePermission,
|
||||
hasPermission,
|
||||
} from "../../utils";
|
||||
import { Constants, hasOnePermission, hasPermission } from "../../utils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { MyAvatar } from "../MyAvatar";
|
||||
import { MyUserAvatar } from "../MyAvatar";
|
||||
import { useSideBarContext } from "../../Contexts/SideBarContext";
|
||||
import { useAppContext } from "../../Contexts/AppContext";
|
||||
|
||||
export default function SideMenu({
|
||||
userSession,
|
||||
|
@ -30,9 +26,10 @@ export default function SideMenu({
|
|||
isSideMenuCollapsed,
|
||||
setIsSideMenuCollapsed,
|
||||
}) {
|
||||
const appContext = useAppContext();
|
||||
const sidebarContext = useSideBarContext();
|
||||
const location = useLocation();
|
||||
const [selectedKeys, setSelectedKeys] = useState("/");
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => setSelectedKeys(location.pathname), [location.pathname]);
|
||||
|
@ -40,13 +37,17 @@ export default function SideMenu({
|
|||
const navigate = useNavigate();
|
||||
|
||||
const getCurrentUsedScannerName = () => {
|
||||
const scannerName = webSocketContext.Scanners.find(
|
||||
/*const scannerName = webSocketContext.Scanners.find(
|
||||
(scanner) => scanner.UsedByUserId === getUserId()
|
||||
)?.Name;
|
||||
|
||||
return scannerName === undefined
|
||||
? t("sideMenu.adminArea.noScannerSelected")
|
||||
: scannerName;
|
||||
: scannerName; */
|
||||
|
||||
// TODO: handle scanner name
|
||||
|
||||
return Constants.LOADING;
|
||||
};
|
||||
|
||||
const getFirstMenuItems = () => {
|
||||
|
@ -57,19 +58,19 @@ export default function SideMenu({
|
|||
key: "/",
|
||||
},
|
||||
];
|
||||
/*
|
||||
|
||||
if (
|
||||
hasPermission(
|
||||
webSocketContext.User.Permissions,
|
||||
appContext.userPermissions,
|
||||
Constants.PERMISSIONS.EQUIPMENT_DOCUMENTATION.VIEW
|
||||
)
|
||||
) { */
|
||||
items.push({
|
||||
label: t("sideMenu.equipmentDocumentation"),
|
||||
icon: <BookOutlined />,
|
||||
key: "/equipment-documentation",
|
||||
});
|
||||
//}
|
||||
) {
|
||||
items.push({
|
||||
label: t("sideMenu.equipmentDocumentation"),
|
||||
icon: <BookOutlined />,
|
||||
key: "/equipment-documentation",
|
||||
});
|
||||
}
|
||||
|
||||
let groupTasks = {
|
||||
label: t("sideMenu.groupTasks.menuCategory"),
|
||||
|
@ -85,7 +86,7 @@ export default function SideMenu({
|
|||
|
||||
if (
|
||||
hasPermission(
|
||||
webSocketContext.User.Permissions,
|
||||
appContext.userPermissions,
|
||||
Constants.PERMISSIONS.GROUP_TASKS.HISTORY
|
||||
)
|
||||
) {
|
||||
|
@ -104,7 +105,7 @@ export default function SideMenu({
|
|||
|
||||
if (
|
||||
hasOnePermission(
|
||||
webSocketContext.User.Permissions,
|
||||
appContext.userPermissions,
|
||||
Constants.PERMISSIONS.ADMIN_AREA.ROLES.CREATE_NEW_ROLE,
|
||||
Constants.PERMISSIONS.ADMIN_AREA.ROLES.UPDATE_ROLE,
|
||||
Constants.PERMISSIONS.ADMIN_AREA.ROLES.DELETE_ROLE,
|
||||
|
@ -121,7 +122,7 @@ export default function SideMenu({
|
|||
|
||||
if (
|
||||
hasOnePermission(
|
||||
webSocketContext.User.Permissions,
|
||||
appContext.userPermissions,
|
||||
Constants.PERMISSIONS.ADMIN_AREA.ROLES.CREATE_NEW_ROLE,
|
||||
Constants.PERMISSIONS.ADMIN_AREA.ROLES.UPDATE_ROLE,
|
||||
Constants.PERMISSIONS.ADMIN_AREA.ROLES.DELETE_ROLE,
|
||||
|
@ -137,7 +138,7 @@ export default function SideMenu({
|
|||
|
||||
if (
|
||||
hasPermission(
|
||||
webSocketContext.User.Permissions,
|
||||
appContext.userPermissions,
|
||||
Constants.PERMISSIONS.ADMIN_AREA.LOGS
|
||||
)
|
||||
) {
|
||||
|
@ -155,11 +156,13 @@ export default function SideMenu({
|
|||
};
|
||||
|
||||
const getSecondMenuItems = () => {
|
||||
console.log("getSecondMenuItems", sidebarContext.connectionBadgeStatus);
|
||||
|
||||
let items = [];
|
||||
|
||||
if (
|
||||
hasPermission(
|
||||
webSocketContext.User.Permissions,
|
||||
appContext.userPermissions,
|
||||
Constants.PERMISSIONS.SCANNER.USE_SCANNERS
|
||||
)
|
||||
) {
|
||||
|
@ -174,9 +177,9 @@ export default function SideMenu({
|
|||
{
|
||||
icon: (
|
||||
<Badge
|
||||
status={webSocketContext.ConnectionBadgeStatus}
|
||||
text={`${webSocketContext.ConnectedWebSocketUsersCount} ${
|
||||
webSocketContext.ConnectedWebSocketUsersCount === 1
|
||||
status={sidebarContext.connectionBadgeStatus}
|
||||
text={`${sidebarContext.connectedUsers} ${
|
||||
sidebarContext.connectedUsers === 1
|
||||
? t("sideMenu.usersCount.single")
|
||||
: t("sideMenu.usersCount.multiple")
|
||||
}`}
|
||||
|
@ -185,13 +188,8 @@ export default function SideMenu({
|
|||
key: "/users",
|
||||
},
|
||||
{
|
||||
label: ` ${webSocketContext.User.Username}`,
|
||||
icon: (
|
||||
<MyAvatar
|
||||
allUsers={webSocketContext.AllUsers}
|
||||
userId={webSocketContext.User.Id}
|
||||
/>
|
||||
),
|
||||
label: ` ${appContext.username}`,
|
||||
icon: <MyUserAvatar avatar={appContext.avatar} />,
|
||||
key: "/user-profile",
|
||||
},
|
||||
{
|
||||
|
@ -216,6 +214,11 @@ export default function SideMenu({
|
|||
return items;
|
||||
};
|
||||
|
||||
console.log(
|
||||
"sidebarContext.connectionBadgeStatus",
|
||||
sidebarContext.connectionBadgeStatus
|
||||
);
|
||||
|
||||
return (
|
||||
<Sider
|
||||
theme="light"
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
import { createContext, useContext, useState } from "react";
|
||||
import { Constants } from "../utils";
|
||||
|
||||
const preview = {
|
||||
username: "",
|
||||
avatar: "",
|
||||
userPermissions: [],
|
||||
availableGroupTasks: [],
|
||||
};
|
||||
|
||||
const AppContext = createContext(preview);
|
||||
|
||||
export const useAppContext = () => useContext(AppContext);
|
||||
|
||||
export function AppProvider({ children }) {
|
||||
const [username, setUsername] = useState(Constants.LOADING);
|
||||
const [avatar, setAvatar] = useState("");
|
||||
const [userPermissions, setUserPermissions] = useState([]);
|
||||
const [availableGroupTasks, setAvailableGroupTasks] = useState([]);
|
||||
|
||||
return (
|
||||
<AppContext.Provider
|
||||
value={{
|
||||
username,
|
||||
setUsername,
|
||||
avatar,
|
||||
setAvatar,
|
||||
userPermissions,
|
||||
setUserPermissions,
|
||||
availableGroupTasks,
|
||||
setAvailableGroupTasks,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</AppContext.Provider>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { createContext, useContext, useState } from "react";
|
||||
|
||||
const preview = {
|
||||
connectionBadgeStatus: "",
|
||||
connectedUsers: 0,
|
||||
selectedScanner: "",
|
||||
};
|
||||
|
||||
const SideBarContext = createContext(preview);
|
||||
|
||||
export const useSideBarContext = () => useContext(SideBarContext);
|
||||
|
||||
export default function SideBarProvider({ children }) {
|
||||
const [connectionBadgeStatus, setConnectionBadgeStatus] = useState("error");
|
||||
const [connectedUsers, setConnectedUsers] = useState(0);
|
||||
const [selectedScanner, setSelectedScanner] = useState("");
|
||||
|
||||
return (
|
||||
<SideBarContext.Provider
|
||||
value={{
|
||||
connectionBadgeStatus,
|
||||
setConnectionBadgeStatus,
|
||||
connectedUsers,
|
||||
setConnectedUsers,
|
||||
selectedScanner,
|
||||
setSelectedScanner,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</SideBarContext.Provider>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import { createContext, useContext, useState } from "react";
|
||||
import { Constants } from "../utils";
|
||||
|
||||
// only for tab completion
|
||||
const preview = {
|
||||
id: Constants.LOADING,
|
||||
avatar: "",
|
||||
username: Constants.LOADING,
|
||||
email: Constants.LOADING,
|
||||
sessions: [],
|
||||
apiKeys: [],
|
||||
};
|
||||
|
||||
const UserProfileContext = createContext({ userProfile: preview });
|
||||
|
||||
export const useUserProfileContext = () => useContext(UserProfileContext);
|
||||
|
||||
export function UserProfileProvider({ children }) {
|
||||
const [userProfile, setUserProfile] = useState(preview);
|
||||
|
||||
return (
|
||||
<UserProfileContext.Provider value={{ userProfile, setUserProfile }}>
|
||||
{children}
|
||||
</UserProfileContext.Provider>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { createContext, useContext, useState } from "react";
|
||||
|
||||
const preview = {
|
||||
roleId: "",
|
||||
users: [],
|
||||
roles: [],
|
||||
};
|
||||
|
||||
const UsersContext = createContext(preview);
|
||||
|
||||
export const useUsersContext = () => useContext(UsersContext);
|
||||
|
||||
export function UsersProvider({ children }) {
|
||||
const [roleId, setRoleId] = useState("");
|
||||
const [users, setUsers] = useState([]);
|
||||
const [roles, setRoles] = useState([]);
|
||||
|
||||
return (
|
||||
<UsersContext.Provider
|
||||
value={{
|
||||
roleId,
|
||||
setRoleId,
|
||||
users,
|
||||
setUsers,
|
||||
roles,
|
||||
setRoles,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</UsersContext.Provider>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
import { createContext, useContext, useEffect, useRef, useState } from "react";
|
||||
import { Constants, ReceivedMessagesCommands, myFetch } from "../utils";
|
||||
import { useSideBarContext } from "./SideBarContext";
|
||||
import { useAppContext } from "./AppContext";
|
||||
import { message } from "antd";
|
||||
|
||||
const WebSocketContext = createContext(null);
|
||||
|
||||
export const useWebSocketContext = () => useContext(WebSocketContext);
|
||||
|
||||
export default function WebSocketProvider({
|
||||
children,
|
||||
userSession,
|
||||
setUserSession,
|
||||
isWebSocketReady,
|
||||
setIsWebSocketReady,
|
||||
}) {
|
||||
const ws = useRef(null);
|
||||
const appContext = useAppContext();
|
||||
const sideBarContext = useSideBarContext();
|
||||
|
||||
const connect = () => {
|
||||
ws.current = new WebSocket(`${Constants.WS_ADDRESS}?auth=${userSession}`);
|
||||
|
||||
ws.current.onopen = () => {
|
||||
console.log("connected");
|
||||
sideBarContext.setConnectionBadgeStatus("success");
|
||||
setIsWebSocketReady(true);
|
||||
|
||||
myFetch("/user/", "GET").then((data) => {
|
||||
console.log("user info", data);
|
||||
|
||||
appContext.setUsername(data.Username);
|
||||
appContext.setAvatar(data.Avatar);
|
||||
appContext.setUserPermissions(data.Permissions);
|
||||
appContext.setAvailableGroupTasks(data.AvailableGroupTasks);
|
||||
});
|
||||
};
|
||||
|
||||
ws.current.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
console.log("received message", data);
|
||||
|
||||
const cmd = data.Cmd;
|
||||
const body = data.Body;
|
||||
|
||||
switch (cmd) {
|
||||
case ReceivedMessagesCommands.UpdateConnectedUsers:
|
||||
sideBarContext.setConnectedUsers(body.WebSocketUsersCount);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
ws.current.onclose = (event) => {
|
||||
setIsWebSocketReady(false);
|
||||
sideBarContext.setConnectionBadgeStatus("error");
|
||||
console.warn("closed", event);
|
||||
|
||||
// custom code defined by the backend server
|
||||
if (event.code === 4001 || event.code === 4002) {
|
||||
//Unauthorized || SessionClosed
|
||||
|
||||
setUserSession();
|
||||
window.location.href = "/";
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.reason.code === 1005) return;
|
||||
|
||||
console.warn("reconnecting...");
|
||||
|
||||
setTimeout(() => connect(), 1000);
|
||||
};
|
||||
};
|
||||
|
||||
const SendSocketMessage = (cmd, body) => {
|
||||
if (isWebSocketReady) {
|
||||
ws.current.send(JSON.stringify({ Cmd: cmd, Body: body }));
|
||||
} else {
|
||||
/*notificationApi["error"]({
|
||||
message: `Websocket is not ready`,
|
||||
description: `Please check your internet connection`,
|
||||
}); */
|
||||
|
||||
message.error(`Websocket is not ready`);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
connect();
|
||||
|
||||
return () => ws.current.close();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<WebSocketContext.Provider value={{ SendSocketMessage: SendSocketMessage }}>
|
||||
{children}
|
||||
</WebSocketContext.Provider>
|
||||
);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export function handleWebSocketMessage(message) {}
|
|
@ -12,20 +12,25 @@ import {
|
|||
Constants,
|
||||
FormatDatetime,
|
||||
SentMessagesCommands,
|
||||
WebSocketContext,
|
||||
getConnectionStatusItem,
|
||||
hasOnePermission,
|
||||
hasPermission,
|
||||
myFetch,
|
||||
} from "../../utils";
|
||||
import { useContext, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { UserAddOutlined } from "@ant-design/icons";
|
||||
import CreateUserModal from "./CreateUserModal";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { MyAvatar } from "../../Components/MyAvatar";
|
||||
import { useUsersContext } from "../../Contexts/UsersContext";
|
||||
import { useAppContext } from "../../Contexts/AppContext";
|
||||
import { useWebSocketContext } from "../../Contexts/WebSocketContext";
|
||||
|
||||
export default function AllUsers() {
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
const webSocketContext = useWebSocketContext();
|
||||
const appContext = useAppContext();
|
||||
const usersContext = useUsersContext();
|
||||
const { t } = useTranslation();
|
||||
const [selectedRoleId, setSelectedRoleId] = useState("");
|
||||
const [notificationApi, notificationContextHolder] =
|
||||
|
@ -63,7 +68,7 @@ export default function AllUsers() {
|
|||
|
||||
if (
|
||||
hasOnePermission(
|
||||
webSocketContext.User.Permissions,
|
||||
appContext.userPermissions,
|
||||
Constants.PERMISSIONS.ALL_USERS.ACTION.CHANGE_ROLE,
|
||||
Constants.PERMISSIONS.ALL_USERS.ACTION.DELETE_USER,
|
||||
Constants.PERMISSIONS.ALL_USERS.ACTION.DEACTIVATE_USER
|
||||
|
@ -75,17 +80,16 @@ export default function AllUsers() {
|
|||
render: (_, record) => (
|
||||
<Space size="middle">
|
||||
{hasPermission(
|
||||
webSocketContext.User.Permissions,
|
||||
appContext.userPermissions,
|
||||
Constants.PERMISSIONS.ALL_USERS.ACTION.CHANGE_ROLE
|
||||
) &&
|
||||
(webSocketContext.AllRoles.find(
|
||||
(role) => role.Id === webSocketContext.User.RoleId
|
||||
(usersContext.roles.find(
|
||||
(role) => role.Id === usersContext.roleId
|
||||
).SortingOrder <
|
||||
webSocketContext.AllRoles.find(
|
||||
(role) => role.Id === record._roleId
|
||||
).SortingOrder ||
|
||||
webSocketContext.AllRoles.find(
|
||||
(role) => role.Id === webSocketContext.User.RoleId
|
||||
usersContext.roles.find((role) => role.Id === record._roleId)
|
||||
.SortingOrder ||
|
||||
usersContext.roles.find(
|
||||
(role) => role.Id === usersContext.roleId
|
||||
).Master) && (
|
||||
<Popconfirm
|
||||
title={t(
|
||||
|
@ -99,29 +103,28 @@ export default function AllUsers() {
|
|||
okButtonProps={{
|
||||
disabled:
|
||||
selectedRoleId ===
|
||||
webSocketContext.AllUsers.find(
|
||||
(user) => user.Id === record.key
|
||||
).RoleId,
|
||||
usersContext.users.find((user) => user.Id === record.key)
|
||||
.RoleId,
|
||||
}}
|
||||
description={
|
||||
<Select
|
||||
style={{ width: 250 }}
|
||||
getPopupContainer={(node) => node.parentNode}
|
||||
defaultValue={
|
||||
webSocketContext.AllUsers.find(
|
||||
usersContext.users.find(
|
||||
(user) => user.Id === record.key
|
||||
).RoleId
|
||||
}
|
||||
value={selectedRoleId}
|
||||
onChange={(e) => setSelectedRoleId(e)}
|
||||
>
|
||||
{webSocketContext.AllRoles.map((role) => {
|
||||
{usersContext.roles.map((role) => {
|
||||
if (
|
||||
webSocketContext.AllRoles.find(
|
||||
(role) => role.Id === webSocketContext.User.RoleId
|
||||
usersContext.roles.find(
|
||||
(role) => role.Id === usersContext.roleId
|
||||
).Master ||
|
||||
webSocketContext.AllRoles.find(
|
||||
(role) => role.Id === webSocketContext.User.RoleId
|
||||
usersContext.roles.find(
|
||||
(role) => role.Id === usersContext.roleId
|
||||
).SortingOrder < role.SortingOrder
|
||||
) {
|
||||
return (
|
||||
|
@ -140,7 +143,7 @@ export default function AllUsers() {
|
|||
to="#"
|
||||
onClick={() => {
|
||||
setSelectedRoleId(
|
||||
webSocketContext.AllUsers.find(
|
||||
usersContext.users.find(
|
||||
(user) => user.Id === record.key
|
||||
).RoleId
|
||||
);
|
||||
|
@ -152,17 +155,16 @@ export default function AllUsers() {
|
|||
)}
|
||||
|
||||
{hasPermission(
|
||||
webSocketContext.User.Permissions,
|
||||
appContext.userPermissions,
|
||||
Constants.PERMISSIONS.ALL_USERS.ACTION.DELETE_USER
|
||||
) &&
|
||||
(webSocketContext.AllRoles.find(
|
||||
(role) => role.Id === webSocketContext.User.RoleId
|
||||
(usersContext.roles.find(
|
||||
(role) => role.Id === usersContext.roleId
|
||||
).SortingOrder <
|
||||
webSocketContext.AllRoles.find(
|
||||
(role) => role.Id === record._roleId
|
||||
).SortingOrder ||
|
||||
webSocketContext.AllRoles.find(
|
||||
(role) => role.Id === webSocketContext.User.RoleId
|
||||
usersContext.roles.find((role) => role.Id === record._roleId)
|
||||
.SortingOrder ||
|
||||
usersContext.roles.find(
|
||||
(role) => role.Id === usersContext.roleId
|
||||
).Master) && (
|
||||
<Popconfirm
|
||||
placement="top"
|
||||
|
@ -175,20 +177,19 @@ export default function AllUsers() {
|
|||
</Popconfirm>
|
||||
)}
|
||||
|
||||
{!webSocketContext.AllUsers.find((user) => user.Id === record.key)
|
||||
{!usersContext.users.find((user) => user.Id === record.key)
|
||||
.Deactivated
|
||||
? hasPermission(
|
||||
webSocketContext.User.Permissions,
|
||||
appContext.userPermissions,
|
||||
Constants.PERMISSIONS.ALL_USERS.ACTION.USER_DEACTIVATION
|
||||
) &&
|
||||
(webSocketContext.AllRoles.find(
|
||||
(role) => role.Id === webSocketContext.User.RoleId
|
||||
(usersContext.roles.find(
|
||||
(role) => role.Id === usersContext.roleId
|
||||
).SortingOrder <
|
||||
webSocketContext.AllRoles.find(
|
||||
(role) => role.Id === record._roleId
|
||||
).SortingOrder ||
|
||||
webSocketContext.AllRoles.find(
|
||||
(role) => role.Id === webSocketContext.User.RoleId
|
||||
usersContext.roles.find((role) => role.Id === record._roleId)
|
||||
.SortingOrder ||
|
||||
usersContext.roles.find(
|
||||
(role) => role.Id === usersContext.roleId
|
||||
).Master) && (
|
||||
<Popconfirm
|
||||
placement="top"
|
||||
|
@ -209,17 +210,16 @@ export default function AllUsers() {
|
|||
</Popconfirm>
|
||||
)
|
||||
: hasPermission(
|
||||
webSocketContext.User.Permissions,
|
||||
appContext.userPermissions,
|
||||
Constants.PERMISSIONS.ALL_USERS.ACTION.USER_DEACTIVATION
|
||||
) &&
|
||||
(webSocketContext.AllRoles.find(
|
||||
(role) => role.Id === webSocketContext.User.RoleId
|
||||
(usersContext.roles.find(
|
||||
(role) => role.Id === usersContext.roleId
|
||||
).SortingOrder <
|
||||
webSocketContext.AllRoles.find(
|
||||
(role) => role.Id === record._roleId
|
||||
).SortingOrder ||
|
||||
webSocketContext.AllRoles.find(
|
||||
(role) => role.Id === webSocketContext.User.RoleId
|
||||
usersContext.roles.find((role) => role.Id === record._roleId)
|
||||
.SortingOrder ||
|
||||
usersContext.roles.find(
|
||||
(role) => role.Id === usersContext.roleId
|
||||
).Master) && (
|
||||
<Popconfirm
|
||||
placement="top"
|
||||
|
@ -247,10 +247,10 @@ export default function AllUsers() {
|
|||
return items;
|
||||
};
|
||||
|
||||
const activatedUsers = webSocketContext.AllUsers.filter(
|
||||
const activatedUsers = usersContext.users.filter(
|
||||
(user) => user.Deactivated === false
|
||||
);
|
||||
const deactivatedUsers = webSocketContext.AllUsers.filter(
|
||||
const deactivatedUsers = usersContext.users.filter(
|
||||
(user) => user.Deactivated === true
|
||||
);
|
||||
|
||||
|
@ -259,8 +259,8 @@ export default function AllUsers() {
|
|||
|
||||
users.sort(
|
||||
(a, b) =>
|
||||
webSocketContext.AllRoles.find((r) => r.Id === a.RoleId).SortingOrder -
|
||||
webSocketContext.AllRoles.find((r) => r.Id === b.RoleId).SortingOrder
|
||||
usersContext.roles.find((r) => r.Id === a.RoleId).SortingOrder -
|
||||
usersContext.roles.find((r) => r.Id === b.RoleId).SortingOrder
|
||||
);
|
||||
|
||||
users.forEach((user) => {
|
||||
|
@ -277,7 +277,7 @@ export default function AllUsers() {
|
|||
</>
|
||||
</Popover>
|
||||
),
|
||||
role: webSocketContext.AllRoles.find((role) => role.Id === user.RoleId)
|
||||
role: usersContext.roles.find((role) => role.Id === user.RoleId)
|
||||
.DisplayName,
|
||||
_roleId: user.RoleId, // used as reference for user deletion
|
||||
connectionStatus: getConnectionStatusItem(user.ConnectionStatus),
|
||||
|
@ -290,7 +290,7 @@ export default function AllUsers() {
|
|||
};
|
||||
|
||||
const onRoleChangeConfirm = (targetUserId) => {
|
||||
const existsRole = webSocketContext.AllRoles.find(
|
||||
const existsRole = usersContext.roles.find(
|
||||
(role) => role.Id === selectedRoleId
|
||||
);
|
||||
|
||||
|
@ -330,6 +330,16 @@ export default function AllUsers() {
|
|||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
myFetch("/users", "GET").then((data) => {
|
||||
console.log("users", data);
|
||||
|
||||
usersContext.setRoleId(data.RoleId);
|
||||
usersContext.setUsers(data.Users);
|
||||
usersContext.setRoles(data.Roles);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
{notificationContextHolder}
|
||||
|
@ -344,7 +354,7 @@ export default function AllUsers() {
|
|||
{t("allUsers.header.allUsers")} ({activatedUsers.length})
|
||||
</Typography.Title>
|
||||
{hasPermission(
|
||||
webSocketContext.User.Permissions,
|
||||
appContext.userPermissions,
|
||||
Constants.PERMISSIONS.ALL_USERS.CREATE_NEW_USER
|
||||
) && (
|
||||
<Button
|
||||
|
@ -363,7 +373,7 @@ export default function AllUsers() {
|
|||
/>
|
||||
|
||||
{hasPermission(
|
||||
webSocketContext.User.Permissions,
|
||||
appContext.userPermissions,
|
||||
Constants.PERMISSIONS.ALL_USERS.ACTION.USER_DEACTIVATION
|
||||
) &&
|
||||
deactivatedUsers.length > 0 && (
|
||||
|
|
|
@ -1,15 +1,5 @@
|
|||
import {
|
||||
Button,
|
||||
Card,
|
||||
Col,
|
||||
Popover,
|
||||
Result,
|
||||
Row,
|
||||
Spin,
|
||||
Typography,
|
||||
} from "antd";
|
||||
import { Card, Col, Popover, Result, Row, Spin, Typography } from "antd";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import CreateEquipmentDocumentationModal from "./CreateEquipmentDocumentationModal";
|
||||
import {
|
||||
AppStyle,
|
||||
|
@ -287,7 +277,7 @@ function DocumentationTypeIcon({ type }) {
|
|||
case 2:
|
||||
return <BookOutlined style={{ fontSize: 24 }} />;
|
||||
default:
|
||||
console.log("DocumentationTypeIcon type not found:", type);
|
||||
console.error("DocumentationTypeIcon type not found:", type);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ import {
|
|||
ArrowUpOutlined,
|
||||
CameraOutlined,
|
||||
DeleteOutlined,
|
||||
EditOutlined,
|
||||
EllipsisOutlined,
|
||||
FullscreenOutlined,
|
||||
PlusOutlined,
|
||||
|
@ -86,8 +85,6 @@ export default function EquipmentDocumentationOverview() {
|
|||
<>
|
||||
<QrScanner
|
||||
onDecode={(result) => {
|
||||
console.log(result);
|
||||
|
||||
if (!isScannedQrCodeValid(result)) {
|
||||
messageApi.error(
|
||||
t(
|
||||
|
@ -100,7 +97,7 @@ export default function EquipmentDocumentationOverview() {
|
|||
setScannerResult(JSON.parse(result).stockitem.toString());
|
||||
setIsScannerActive(false);
|
||||
}}
|
||||
onError={(error) => console.log(error?.message)}
|
||||
onError={(error) => console.error(error?.message)}
|
||||
/>
|
||||
<Button
|
||||
block
|
||||
|
|
|
@ -14,13 +14,12 @@ import {
|
|||
Upload,
|
||||
notification,
|
||||
} from "antd";
|
||||
import { useContext, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
Constants,
|
||||
EncodeStringToBase64,
|
||||
FormatDatetime,
|
||||
SentMessagesCommands,
|
||||
WebSocketContext,
|
||||
getConnectionStatusItem,
|
||||
getUserSessionFromLocalStorage,
|
||||
hasPermission,
|
||||
|
@ -36,14 +35,19 @@ import {
|
|||
FileTextOutlined,
|
||||
KeyOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { MyAvatar } from "../../Components/MyAvatar";
|
||||
import { MyUserAvatar } from "../../Components/MyAvatar";
|
||||
import { useUserProfileContext } from "../../Contexts/UserProfileContext";
|
||||
import { useWebSocketContext } from "../../Contexts/WebSocketContext";
|
||||
|
||||
export default function UserProfile() {
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
const webSocketContext = useWebSocketContext();
|
||||
const { userProfile, setUserProfile } = useUserProfileContext();
|
||||
const [notificationApi, notificationContextHolder] =
|
||||
notification.useNotification();
|
||||
const { t, i18n } = useTranslation();
|
||||
|
||||
const [username, setUsername] = useState(Constants.LOADING);
|
||||
const [email, setEmail] = useState(Constants.LOADING);
|
||||
const [oldPassword, setOldPassword] = useState("");
|
||||
const [newPassword, setNewPassword] = useState("");
|
||||
const [repeatedNewPassword, setRepeatedNewPassword] = useState("");
|
||||
|
@ -178,7 +182,7 @@ export default function UserProfile() {
|
|||
const getApiKeyTableItems = () => {
|
||||
let items = [];
|
||||
|
||||
webSocketContext.User.ApiKeys.forEach((apiKey) => {
|
||||
userProfile.apiKeys.forEach((apiKey) => {
|
||||
items.push({
|
||||
key: apiKey.Id,
|
||||
name: apiKey.Name,
|
||||
|
@ -195,11 +199,11 @@ export default function UserProfile() {
|
|||
const getSessionTableItems = () => {
|
||||
let items = [];
|
||||
|
||||
webSocketContext.User.Sessions.sort(
|
||||
userProfile.sessions.sort(
|
||||
(a, b) => b.ConnectionStatus - a.ConnectionStatus
|
||||
);
|
||||
|
||||
webSocketContext.User.Sessions.forEach((session) => {
|
||||
userProfile.sessions.forEach((session) => {
|
||||
items.push({
|
||||
key: session.IdForDeletion,
|
||||
userAgent: session.UserAgent,
|
||||
|
@ -228,17 +232,15 @@ export default function UserProfile() {
|
|||
|
||||
const isButtonDisabled = () => {
|
||||
if (
|
||||
!isEmailValid(webSocketContext.UserProfileStateEmail) ||
|
||||
webSocketContext.UserProfileStateUsername.length <
|
||||
Constants.GLOBALS.MIN_USERNAME_LENGTH
|
||||
!isEmailValid(email) ||
|
||||
userProfile.username.length < Constants.GLOBALS.MIN_USERNAME_LENGTH
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
webSocketContext.UserProfileStateUsername !==
|
||||
webSocketContext.User.Username ||
|
||||
webSocketContext.UserProfileStateEmail !== webSocketContext.User.Email ||
|
||||
username !== userProfile.username ||
|
||||
email !== userProfile.email ||
|
||||
(oldPassword !== "" &&
|
||||
newPassword !== "" &&
|
||||
newPassword === repeatedNewPassword)
|
||||
|
@ -252,17 +254,12 @@ export default function UserProfile() {
|
|||
const handleOnSubmit = () => {
|
||||
const changes = {};
|
||||
|
||||
if (
|
||||
webSocketContext.User.Username !==
|
||||
webSocketContext.UserProfileStateUsername
|
||||
) {
|
||||
changes.username = webSocketContext.UserProfileStateUsername;
|
||||
if (userProfile.username !== username) {
|
||||
changes.username = username;
|
||||
}
|
||||
|
||||
if (
|
||||
webSocketContext.User.Email !== webSocketContext.UserProfileStateEmail
|
||||
) {
|
||||
changes.email = webSocketContext.UserProfileStateEmail;
|
||||
if (userProfile.email !== email) {
|
||||
changes.email = email;
|
||||
}
|
||||
|
||||
if (
|
||||
|
@ -288,6 +285,22 @@ export default function UserProfile() {
|
|||
setNewApikeyName("");
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
myFetch("/user/profile", "GET").then((data) => {
|
||||
setUserProfile({
|
||||
id: data.Id,
|
||||
avatar: data.Avatar,
|
||||
username: data.Username,
|
||||
email: data.Email,
|
||||
sessions: data.Sessions,
|
||||
apiKeys: data.ApiKeys,
|
||||
});
|
||||
|
||||
setUsername(data.Username);
|
||||
setEmail(data.Email);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
{notificationContextHolder}
|
||||
|
@ -310,11 +323,7 @@ export default function UserProfile() {
|
|||
"X-Authorization": getUserSessionFromLocalStorage(),
|
||||
}}
|
||||
>
|
||||
<MyAvatar
|
||||
avatarWidth={200}
|
||||
allUsers={webSocketContext.AllUsers}
|
||||
userId={webSocketContext.User.Id}
|
||||
/>
|
||||
<MyUserAvatar avatar={userProfile.avatar} size={256} />
|
||||
</Upload>
|
||||
</Col>
|
||||
|
||||
|
@ -343,14 +352,13 @@ export default function UserProfile() {
|
|||
label={t("userProfile.form.username")}
|
||||
hasFeedback
|
||||
validateStatus={
|
||||
webSocketContext.UserProfileStateUsername.length <
|
||||
Constants.GLOBALS.MIN_USERNAME_LENGTH && "error"
|
||||
username < Constants.GLOBALS.MIN_USERNAME_LENGTH && "error"
|
||||
}
|
||||
>
|
||||
<Input
|
||||
value={webSocketContext.UserProfileStateUsername}
|
||||
value={userProfile.username}
|
||||
onChange={(e) =>
|
||||
webSocketContext.setUserProfileStateUsername(e.target.value)
|
||||
setUserProfile({ ...userProfile, Username: e.target.value })
|
||||
}
|
||||
minLength={Constants.GLOBALS.MIN_USERNAME_LENGTH}
|
||||
maxLength={Constants.GLOBALS.MAX_USERNAME_LENGTH}
|
||||
|
@ -359,15 +367,13 @@ export default function UserProfile() {
|
|||
<Form.Item
|
||||
label={t("userProfile.form.email")}
|
||||
hasFeedback
|
||||
validateStatus={
|
||||
!isEmailValid(webSocketContext.UserProfileStateEmail) && "error"
|
||||
}
|
||||
validateStatus={!isEmailValid(userProfile.email) && "error"}
|
||||
>
|
||||
<Input
|
||||
type="email"
|
||||
value={webSocketContext.UserProfileStateEmail}
|
||||
value={userProfile.email}
|
||||
onChange={(e) =>
|
||||
webSocketContext.setUserProfileStateEmail(e.target.value)
|
||||
setUserProfile({ ...userProfile, Email: e.target.value })
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
@ -431,8 +437,7 @@ export default function UserProfile() {
|
|||
<br />
|
||||
|
||||
<Typography.Title level={4}>
|
||||
{t("userProfile.header.yourSessions")} (
|
||||
{webSocketContext.User.Sessions.length})
|
||||
{t("userProfile.header.yourSessions")} ({userProfile.sessions.length})
|
||||
</Typography.Title>
|
||||
|
||||
<Table
|
||||
|
@ -442,7 +447,7 @@ export default function UserProfile() {
|
|||
/>
|
||||
|
||||
{hasPermission(
|
||||
webSocketContext.User.Permissions,
|
||||
userProfile.Permissions,
|
||||
Constants.PERMISSIONS.USER_PROFILE.API_KEYS
|
||||
) && (
|
||||
<>
|
||||
|
@ -455,7 +460,7 @@ export default function UserProfile() {
|
|||
>
|
||||
<Typography.Title level={4}>
|
||||
{t("userProfile.header.yourApiKeys")} (
|
||||
{webSocketContext.User.ApiKeys.length}){" "}
|
||||
{userProfile.apiKeys.length}){" "}
|
||||
<Tooltip title={t("userProfile.icon.viewApiDoc")}>
|
||||
<Link
|
||||
target="_blank"
|
||||
|
|
21
src/utils.js
21
src/utils.js
|
@ -130,6 +130,7 @@ export const Constants = {
|
|||
INFO: 0,
|
||||
ERROR: 1,
|
||||
},
|
||||
LOADING: "loading...",
|
||||
};
|
||||
|
||||
export const AppStyle = {
|
||||
|
@ -224,7 +225,7 @@ let webSocketContextPreview = {
|
|||
export const WebSocketContext = createContext(webSocketContextPreview);
|
||||
|
||||
// commands received from the backend server
|
||||
const ReceivedMessagesCommands = {
|
||||
export const ReceivedMessagesCommands = {
|
||||
InitUserSocketConnection: 1,
|
||||
UpdateConnectedUsers: 2,
|
||||
NewGroupTaskStarted: 3,
|
||||
|
@ -1272,27 +1273,31 @@ export function CapitalizeFirstLetter(string) {
|
|||
}
|
||||
|
||||
export function hasPermission(userPermissions, permission) {
|
||||
return userPermissions.includes(permission);
|
||||
return true;
|
||||
//return userPermissions.includes(permission);
|
||||
}
|
||||
|
||||
export function hasXYPermission(userPermissions, permission, xyValue) {
|
||||
return userPermissions.includes(
|
||||
return true;
|
||||
/*return userPermissions.includes(
|
||||
permission.replace("XY", xyValue.toLowerCase())
|
||||
);
|
||||
); */
|
||||
}
|
||||
|
||||
export function hasOnePermission(userPermissions, ...permissions) {
|
||||
for (const permission of permissions) {
|
||||
return true;
|
||||
/*for (const permission of permissions) {
|
||||
if (userPermissions.includes(permission)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false; */
|
||||
}
|
||||
|
||||
export function hasOneXYPermission(userPermissions, xyValue, ...permissions) {
|
||||
for (const permission of permissions) {
|
||||
return true;
|
||||
/* for (const permission of permissions) {
|
||||
if (
|
||||
userPermissions.includes(permission.replace("XY", xyValue.toLowerCase()))
|
||||
) {
|
||||
|
@ -1300,7 +1305,7 @@ export function hasOneXYPermission(userPermissions, xyValue, ...permissions) {
|
|||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false; */
|
||||
}
|
||||
|
||||
export function EncodeStringToBase64(value) {
|
||||
|
|
Loading…
Reference in New Issue