multiple contexts

main
alex 2023-08-27 18:59:01 +02:00
parent ba5d3e9d20
commit 9d76ac0cd8
24 changed files with 1488 additions and 404 deletions

View File

@ -8,8 +8,14 @@ import DashboardLayout from "./Components/DashboardLayout";
import WebSocketProvider from "./Contexts/WebSocketContext"; import WebSocketProvider from "./Contexts/WebSocketContext";
import SideBarProvider from "./Contexts/SideBarContext"; import SideBarProvider from "./Contexts/SideBarContext";
import { AppProvider } from "./Contexts/AppContext"; import { AppProvider } from "./Contexts/AppContext";
import { GroupTasksProvider } from "./Contexts/GroupTasksContext";
import { AdminAreaRolesProvider } from "./Contexts/AdminAreaRolesContext";
import { UserProfileProvider } from "./Contexts/UserProfileContext";
import { UsersProvider } from "./Contexts/UsersContext";
export default function App() { export default function App() {
const [notificationApi, notificationContextHolder] =
notification.useNotification();
const { userSession, setUserSession } = UseUserSession(); const { userSession, setUserSession } = UseUserSession();
const [isWebSocketReady, setIsWebSocketReady] = useState(true); const [isWebSocketReady, setIsWebSocketReady] = useState(true);
@ -26,13 +32,20 @@ export default function App() {
return ( return (
<Layout style={{ minHeight: "100vh" }}> <Layout style={{ minHeight: "100vh" }}>
{notificationContextHolder}
<AppProvider> <AppProvider>
<SideBarProvider> <SideBarProvider>
<GroupTasksProvider>
<AdminAreaRolesProvider>
<UserProfileProvider>
<UsersProvider>
<WebSocketProvider <WebSocketProvider
userSession={userSession} userSession={userSession}
setUserSession={setUserSession} setUserSession={setUserSession}
isWebSocketReady={isWebSocketReady} isWebSocketReady={isWebSocketReady}
setIsWebSocketReady={setIsWebSocketReady} setIsWebSocketReady={setIsWebSocketReady}
notificationApi={notificationApi}
> >
<ReconnectingView isWebSocketReady={isWebSocketReady} /> <ReconnectingView isWebSocketReady={isWebSocketReady} />
@ -41,6 +54,10 @@ export default function App() {
setUserSession={setUserSession} setUserSession={setUserSession}
/> />
</WebSocketProvider> </WebSocketProvider>
</UsersProvider>
</UserProfileProvider>
</AdminAreaRolesProvider>
</GroupTasksProvider>
</SideBarProvider> </SideBarProvider>
</AppProvider> </AppProvider>
</Layout> </Layout>

View File

@ -1,200 +1,180 @@
import { Route, Routes } from "react-router-dom"; import { Route, Routes } from "react-router-dom";
import Dashboard from "../../Pages/Dashboard"; import { Constants, hasOnePermission, hasPermission } from "../../utils";
import { import { useAppContext } from "../../Contexts/AppContext";
Constants, import { Suspense, lazy } from "react";
WebSocketContext, import { Spin } from "antd";
hasOnePermission,
hasPermission, // Lazy-loaded components
} from "../../utils"; const Dashboard = lazy(() => import("../../Pages/Dashboard"));
import UserProfile from "../../Pages/UserProfile"; const GroupTasks = lazy(() => import("../../Pages/GroupTasks/Overview"));
import Scanners from "../../Pages/Scanners"; const UserProfile = lazy(() => import("../../Pages/UserProfile"));
import AdminAreaRoles from "../../Pages/AdminArea/Roles"; const Scanners = lazy(() => import("../../Pages/Scanners"));
import AdminAreaLogs from "../../Pages/AdminArea/Logs"; const AdminAreaRoles = lazy(() => import("../../Pages/AdminArea/Roles"));
import AllUsers from "../../Pages/AllUsers"; const AdminAreaLogs = lazy(() => import("../../Pages/AdminArea/Logs"));
import GroupTasks from "../../Pages/GroupTasks/Overview"; const AllUsers = lazy(() => import("../../Pages/AllUsers"));
import GroupTasksHistory from "../../Pages/GroupTasks/History"; const GroupTasksHistory = lazy(() => import("../../Pages/GroupTasks/History"));
import PageNotFound from "../../Pages/PageNotFound"; const PageNotFound = lazy(() => import("../../Pages/PageNotFound"));
import EquipmentDocumentationOverview from "../../Pages/EquipmentDocumentation"; const EquipmentDocumentationOverview = lazy(() =>
import { UserProfileProvider } from "../../Contexts/UserProfileContext"; import("../../Pages/EquipmentDocumentation")
import { UsersProvider } from "../../Contexts/UsersContext"; );
function SuspenseFallback({ children }) {
return (
<Suspense
fallback={
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "center",
alignContent: "center",
alignItems: "center",
textAlign: "center",
height: "98.3vh",
}}
>
<Spin size="large" />
</div>
}
>
{children}
</Suspense>
);
}
export default function AppRoutes() { export default function AppRoutes() {
// const webSocketContext = useContext(WebSocketContext); const appContext = useAppContext();
console.log("appRoutes"); console.info("appRoutes");
/*
TODO: move down
{hasPermission(
webSocketContext.User.Permissions,
Constants.PERMISSIONS.EQUIPMENT_DOCUMENTATION.VIEW
) && (
<Route
path="/equipment-documentation"
element={<EquipmentDocumentation />}
/>
)}
<Route
path={
Constants.ROUTE_PATHS.EQUIPMENT_DOCUMENTATION_VIEW +
":paramEquipmentId"
}
element={<EquipmentDocumentation isEquipmentViewModalOpen={true} />}
/>
<Route
path={
Constants.ROUTE_PATHS.EQUIPMENT_DOCUMENTATION + "/:paramStockItemId"
}
element={<ViewEquipmentDocumentations />}
/>
*/
return ( return (
<Routes> <Routes>
<Route path="/" element={<Dashboard />} /> <Route
path="/"
element={
<SuspenseFallback>
<Dashboard />
</SuspenseFallback>
}
/>
{hasPermission(
appContext.userPermissions,
Constants.PERMISSIONS.EQUIPMENT_DOCUMENTATION.VIEW
) && (
<Route <Route
path={Constants.ROUTE_PATHS.EQUIPMENT_DOCUMENTATION} path={Constants.ROUTE_PATHS.EQUIPMENT_DOCUMENTATION}
element={<EquipmentDocumentationOverview />} element={
<SuspenseFallback>
<EquipmentDocumentationOverview />
</SuspenseFallback>
}
/> />
)}
<Route <Route
path={Constants.ROUTE_PATHS.GROUP_TASKS} path={Constants.ROUTE_PATHS.GROUP_TASKS}
element={<GroupTasks isGroupTasksViewModalOpen={false} />} element={
<SuspenseFallback>
<GroupTasks isGroupTasksViewModalOpen={false} />
</SuspenseFallback>
}
/> />
<Route <Route
path={Constants.ROUTE_PATHS.GROUP_TASKS_VIEW + ":paramGroupTaskId"} path={Constants.ROUTE_PATHS.GROUP_TASKS_VIEW + ":paramGroupTaskId"}
element={<GroupTasks isGroupTasksViewModalOpen={true} />} element={
<SuspenseFallback>
<GroupTasks isGroupTasksViewModalOpen={true} />
</SuspenseFallback>
}
/> />
{hasPermission(
appContext.userPermissions,
Constants.PERMISSIONS.GROUP_TASKS.HISTORY
) && (
<Route <Route
path={Constants.ROUTE_PATHS.GROUP_TASKS + "-history"} path={Constants.ROUTE_PATHS.GROUP_TASKS + "-history"}
element={<GroupTasksHistory />} element={
<SuspenseFallback>
<GroupTasksHistory />
</SuspenseFallback>
}
/> />
)}
<Route path="/scanners" element={<Scanners />} /> {hasPermission(
appContext.userPermissions,
Constants.PERMISSIONS.SCANNER.USE_SCANNERS
) && (
<Route
path="/scanners"
element={
<SuspenseFallback>
<Scanners />
</SuspenseFallback>
}
/>
)}
<Route <Route
path="/users" path="/users"
element={ element={
<UsersProvider> <SuspenseFallback>
<AllUsers /> <AllUsers />
</UsersProvider> </SuspenseFallback>
} }
/> />
<Route <Route
path="/user-profile" path="/user-profile"
element={ element={
<UserProfileProvider> <SuspenseFallback>
<UserProfile /> <UserProfile />
</UserProfileProvider> </SuspenseFallback>
} }
/> />
<Route path="/admin-area/roles" element={<AdminAreaRoles />} />
<Route path="/admin-area/logs" element={<AdminAreaLogs />} />
<Route path="*" element={<PageNotFound />} />
</Routes>
);
} /*
/*
export default function AppRoutes() {
const webSocketContext = useContext(WebSocketContext);
/*
TODO: move down
{hasPermission(
webSocketContext.User.Permissions,
Constants.PERMISSIONS.EQUIPMENT_DOCUMENTATION.VIEW
) && (
<Route
path="/equipment-documentation"
element={<EquipmentDocumentation />}
/>
)}
<Route
path={
Constants.ROUTE_PATHS.EQUIPMENT_DOCUMENTATION_VIEW +
":paramEquipmentId"
}
element={<EquipmentDocumentation isEquipmentViewModalOpen={true} />}
/>
<Route
path={
Constants.ROUTE_PATHS.EQUIPMENT_DOCUMENTATION + "/:paramStockItemId"
}
element={<ViewEquipmentDocumentations />}
/>
*/ /*
return (
<Routes>
<Route path="/" element={<Dashboard />} />
<Route
path={Constants.ROUTE_PATHS.EQUIPMENT_DOCUMENTATION}
element={<EquipmentDocumentationOverview />}
/>
<Route
path={Constants.ROUTE_PATHS.GROUP_TASKS}
element={<GroupTasks isGroupTasksViewModalOpen={false} />}
/>
<Route
path={Constants.ROUTE_PATHS.GROUP_TASKS_VIEW + ":paramGroupTaskId"}
element={<GroupTasks isGroupTasksViewModalOpen={true} />}
/>
{hasPermission(
webSocketContext.User.Permissions,
Constants.PERMISSIONS.GROUP_TASKS.HISTORY
) && (
<Route
path={Constants.ROUTE_PATHS.GROUP_TASKS + "-history"}
element={<GroupTasksHistory />}
/>
)}
{hasPermission(
webSocketContext.User.Permissions,
Constants.PERMISSIONS.SCANNER.USE_SCANNERS
) && <Route path="/scanners" element={<Scanners />} />}
<Route path="/users" element={<AllUsers />} />
<Route path="/user-profile" element={<UserProfile />} />
{hasOnePermission( {hasOnePermission(
webSocketContext.User.Permissions, appContext.userPermissions,
Constants.PERMISSIONS.ADMIN_AREA.ROLES.CREATE_NEW_ROLE, Constants.PERMISSIONS.ADMIN_AREA.ROLES.CREATE_NEW_ROLE,
Constants.PERMISSIONS.ADMIN_AREA.ROLES.UPDATE_ROLE, Constants.PERMISSIONS.ADMIN_AREA.ROLES.UPDATE_ROLE,
Constants.PERMISSIONS.ADMIN_AREA.ROLES.DELETE_ROLE, Constants.PERMISSIONS.ADMIN_AREA.ROLES.DELETE_ROLE,
Constants.PERMISSIONS.ADMIN_AREA.ROLES.MOVE_ROLE_UP_DOWN Constants.PERMISSIONS.ADMIN_AREA.ROLES.MOVE_ROLE_UP_DOWN
) && <Route path="/admin-area/roles" element={<AdminAreaRoles />} />} ) && (
<Route
path="/admin-area/roles"
element={
<SuspenseFallback>
<AdminAreaRoles />
</SuspenseFallback>
}
/>
)}
{hasPermission( {hasPermission(
webSocketContext.User.Permissions, appContext.userPermissions,
Constants.PERMISSIONS.ADMIN_AREA.LOGS Constants.PERMISSIONS.ADMIN_AREA.LOGS
) && <Route path="/admin-area/logs" element={<AdminAreaLogs />} />} ) && (
<Route
path="/admin-area/logs"
element={
<SuspenseFallback>
<AdminAreaLogs />
</SuspenseFallback>
}
/>
)}
<Route path="*" element={<PageNotFound />} /> <Route
path="*"
element={
<SuspenseFallback>
<PageNotFound />
</SuspenseFallback>
}
/>
</Routes> </Routes>
); );
} }
*/

View File

@ -4,21 +4,16 @@ import {
ReloadOutlined, ReloadOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import { Card, Checkbox, Popover, Space, Spin, Tooltip } from "antd"; import { Card, Checkbox, Popover, Space, Spin, Tooltip } from "antd";
import { useContext, useEffect, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { import { Constants, FormatDatetime, myFetch } from "../../utils";
Constants,
FormatDatetime,
WebSocketContext,
myFetch,
} from "../../utils";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
export default function LogCard({ type }) { export default function LogCard({ type }) {
const webSocketContext = useContext(WebSocketContext);
const { t, i18n } = useTranslation(); const { t, i18n } = useTranslation();
const [checkboxInfoChecked, setCheckboxInfoChecked] = useState(true); const [checkboxInfoChecked, setCheckboxInfoChecked] = useState(true);
const [checkboxErrorChecked, setCheckboxErrorChecked] = useState(true); const [checkboxErrorChecked, setCheckboxErrorChecked] = useState(true);
const fetchResponse = useRef();
const getDate = () => { const getDate = () => {
const today = new Date(); const today = new Date();
@ -56,16 +51,16 @@ export default function LogCard({ type }) {
}; };
const getGroupTaskStepName = (groupTaskStep) => { const getGroupTaskStepName = (groupTaskStep) => {
const foundName = webSocketContext.CategoryGroups.find( const foundName = fetchResponse.current.CategoryGroups.find(
(categoryGroup) => (categoryGroup) =>
categoryGroup.category === categoryGroup.category ===
webSocketContext.GroupTasks.find( fetchResponse.current.GroupTasks.find(
(groupTask) => groupTask.Id === groupTaskStep.GroupTasksId (groupTask) => groupTask.Id === groupTaskStep.GroupTasksId
)?.Category )?.Category
)?.groups.find( )?.groups.find(
(groups) => (groups) =>
groups.id === groups.id ===
webSocketContext.GroupTasks.find( fetchResponse.current.GroupTasks.find(
(groupTask) => groupTask.Id === groupTaskStep.GroupTasksId (groupTask) => groupTask.Id === groupTaskStep.GroupTasksId
).GroupId ).GroupId
).tasks[groupTaskStep.Step - 1]; ).tasks[groupTaskStep.Step - 1];
@ -83,6 +78,8 @@ export default function LogCard({ type }) {
"GET" "GET"
) )
.then((data) => { .then((data) => {
fetchResponse.current = data;
setLoadingSpinner(false); setLoadingSpinner(false);
if (data.Logs === null) { if (data.Logs === null) {
@ -119,7 +116,7 @@ export default function LogCard({ type }) {
); );
if (foundData !== undefined) { if (foundData !== undefined) {
const foundUser = webSocketContext.AllUsers.find( const foundUser = fetchResponse.current.Users.find(
(user) => user.Id === foundData.Value (user) => user.Id === foundData.Value
); );
@ -145,7 +142,8 @@ export default function LogCard({ type }) {
); );
if (foundData !== undefined) { if (foundData !== undefined) {
const foundGroupTask = webSocketContext.GroupTasks.find( const foundGroupTask =
fetchResponse.current.GroupTasks.find(
(groupTask) => groupTask.Id === foundData.Value (groupTask) => groupTask.Id === foundData.Value
); );
@ -194,7 +192,7 @@ export default function LogCard({ type }) {
if (foundData !== undefined) { if (foundData !== undefined) {
const foundGroupTaskStep = const foundGroupTaskStep =
webSocketContext.GroupTasksSteps.find( fetchResponse.current.GroupTasksSteps.find(
(step) => step.Id === foundData.Value (step) => step.Id === foundData.Value
); );
@ -243,7 +241,7 @@ export default function LogCard({ type }) {
); );
if (foundData !== undefined) { if (foundData !== undefined) {
const foundRole = webSocketContext.AllRoles.find( const foundRole = fetchResponse.current.Roles.find(
(role) => role.Id === foundData.Value (role) => role.Id === foundData.Value
); );
@ -295,7 +293,8 @@ export default function LogCard({ type }) {
foundDataCategory !== undefined && foundDataCategory !== undefined &&
foundDataGroupId !== undefined foundDataGroupId !== undefined
) { ) {
const foundGroup = webSocketContext.CategoryGroups.find( const foundGroup =
fetchResponse.current.CategoryGroups.find(
(categoryGroup) => (categoryGroup) =>
categoryGroup.category === foundDataCategory.Value categoryGroup.category === foundDataCategory.Value
).groups.find( ).groups.find(

View File

@ -34,7 +34,6 @@ export default function PageContent({
</Header> </Header>
<Content <Content
//style={{ margin: 12, marginLeft: 212, width: "75%", height: "100%" }}
style={{ style={{
padding: 12, padding: 12,
}} }}
@ -44,5 +43,3 @@ export default function PageContent({
</Layout> </Layout>
); );
} }
// <AppRoutes />

View File

@ -11,7 +11,7 @@ import {
} from "@ant-design/icons"; } from "@ant-design/icons";
import { Badge, Divider, Menu } from "antd"; import { Badge, Divider, Menu } from "antd";
import Sider from "antd/es/layout/Sider"; import Sider from "antd/es/layout/Sider";
import { useContext, useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { Constants, hasOnePermission, hasPermission } from "../../utils"; import { Constants, hasOnePermission, hasPermission } from "../../utils";
@ -27,7 +27,7 @@ export default function SideMenu({
setIsSideMenuCollapsed, setIsSideMenuCollapsed,
}) { }) {
const appContext = useAppContext(); const appContext = useAppContext();
const sidebarContext = useSideBarContext(); const sideBarContext = useSideBarContext();
const location = useLocation(); const location = useLocation();
const [selectedKeys, setSelectedKeys] = useState("/"); const [selectedKeys, setSelectedKeys] = useState("/");
const { t } = useTranslation(); const { t } = useTranslation();
@ -156,8 +156,6 @@ export default function SideMenu({
}; };
const getSecondMenuItems = () => { const getSecondMenuItems = () => {
console.log("getSecondMenuItems", sidebarContext.connectionBadgeStatus);
let items = []; let items = [];
if ( if (
@ -177,9 +175,9 @@ export default function SideMenu({
{ {
icon: ( icon: (
<Badge <Badge
status={sidebarContext.connectionBadgeStatus} status={sideBarContext.connectionBadgeStatus}
text={`${sidebarContext.connectedUsers} ${ text={`${sideBarContext.connectedUsers} ${
sidebarContext.connectedUsers === 1 sideBarContext.connectedUsers === 1
? t("sideMenu.usersCount.single") ? t("sideMenu.usersCount.single")
: t("sideMenu.usersCount.multiple") : t("sideMenu.usersCount.multiple")
}`} }`}
@ -188,8 +186,8 @@ export default function SideMenu({
key: "/users", key: "/users",
}, },
{ {
label: ` ${appContext.username}`, label: ` ${sideBarContext.username}`,
icon: <MyUserAvatar avatar={appContext.avatar} />, icon: <MyUserAvatar avatar={sideBarContext.avatar} />,
key: "/user-profile", key: "/user-profile",
}, },
{ {
@ -214,11 +212,6 @@ export default function SideMenu({
return items; return items;
}; };
console.log(
"sidebarContext.connectionBadgeStatus",
sidebarContext.connectionBadgeStatus
);
return ( return (
<Sider <Sider
theme="light" theme="light"

View File

@ -0,0 +1,28 @@
import { createContext, useContext, useState } from "react";
const preview = {
roles: [],
rolesPermissions: [],
};
const AdminAreaRolesContext = createContext(preview);
export const useAdminAreaRolesContext = () => useContext(AdminAreaRolesContext);
export function AdminAreaRolesProvider({ children }) {
const [roles, setRoles] = useState([]);
const [rolesPermissions, setRolesPermissions] = useState([]);
return (
<AdminAreaRolesContext.Provider
value={{
roles,
setRoles,
rolesPermissions,
setRolesPermissions,
}}
>
{children}
</AdminAreaRolesContext.Provider>
);
}

View File

@ -1,11 +1,9 @@
import { createContext, useContext, useState } from "react"; import { createContext, useContext, useRef, useState } from "react";
import { Constants } from "../utils";
const preview = { const preview = {
username: "", userId: "",
avatar: "",
userPermissions: [], userPermissions: [],
availableGroupTasks: [], users: [],
}; };
const AppContext = createContext(preview); const AppContext = createContext(preview);
@ -13,22 +11,19 @@ const AppContext = createContext(preview);
export const useAppContext = () => useContext(AppContext); export const useAppContext = () => useContext(AppContext);
export function AppProvider({ children }) { export function AppProvider({ children }) {
const [username, setUsername] = useState(Constants.LOADING); const userId = useRef(""); // used for some conditions in webSocket message handler
const [avatar, setAvatar] = useState("");
const [userPermissions, setUserPermissions] = useState([]); const [userPermissions, setUserPermissions] = useState([]);
const [availableGroupTasks, setAvailableGroupTasks] = useState([]); const [users, setUsers] = useState([]); // TODO: realy need this?
return ( return (
<AppContext.Provider <AppContext.Provider
value={{ value={{
username, userId,
setUsername,
avatar,
setAvatar,
userPermissions, userPermissions,
setUserPermissions, setUserPermissions,
availableGroupTasks, users,
setAvailableGroupTasks, setUsers,
}} }}
> >
{children} {children}

View File

@ -0,0 +1,35 @@
import { createContext, useContext, useRef, useState } from "react";
const preview = {
categoryGroups: [],
groupTasks: [],
groupTasksSteps: [],
startGroupTasksOpenModalRememberIdRef: null,
};
const GroupTasksContext = createContext(preview);
export const useGroupTasksContext = () => useContext(GroupTasksContext);
export function GroupTasksProvider({ children }) {
const [categoryGroups, setCategoryGroups] = useState([]);
const [groupTasks, setGroupTasks] = useState([]);
const [groupTasksSteps, setGroupTasksSteps] = useState([]);
const startGroupTasksOpenModalRememberIdRef = useRef(null);
return (
<GroupTasksContext.Provider
value={{
categoryGroups,
setCategoryGroups,
groupTasks,
setGroupTasks,
groupTasksSteps,
setGroupTasksSteps,
startGroupTasksOpenModalRememberIdRef,
}}
>
{children}
</GroupTasksContext.Provider>
);
}

View File

@ -1,9 +1,13 @@
import { createContext, useContext, useState } from "react"; import { createContext, useContext, useState } from "react";
import { Constants } from "../utils";
const preview = { const preview = {
connectionBadgeStatus: "", connectionBadgeStatus: "",
connectedUsers: 0, connectedUsers: 0,
selectedScanner: "", selectedScanner: "",
username: "",
avatar: "",
availableGroupTasks: [],
}; };
const SideBarContext = createContext(preview); const SideBarContext = createContext(preview);
@ -14,6 +18,9 @@ export default function SideBarProvider({ children }) {
const [connectionBadgeStatus, setConnectionBadgeStatus] = useState("error"); const [connectionBadgeStatus, setConnectionBadgeStatus] = useState("error");
const [connectedUsers, setConnectedUsers] = useState(0); const [connectedUsers, setConnectedUsers] = useState(0);
const [selectedScanner, setSelectedScanner] = useState(""); const [selectedScanner, setSelectedScanner] = useState("");
const [username, setUsername] = useState(Constants.LOADING); //
const [avatar, setAvatar] = useState("");
const [availableGroupTasks, setAvailableGroupTasks] = useState([]);
return ( return (
<SideBarContext.Provider <SideBarContext.Provider
@ -24,6 +31,12 @@ export default function SideBarProvider({ children }) {
setConnectedUsers, setConnectedUsers,
selectedScanner, selectedScanner,
setSelectedScanner, setSelectedScanner,
username,
setUsername,
avatar,
setAvatar,
availableGroupTasks,
setAvailableGroupTasks,
}} }}
> >
{children} {children}

View File

@ -1,25 +1,33 @@
import { createContext, useContext, useState } from "react"; import { createContext, useContext, useState } from "react";
import { Constants } from "../utils"; import { Constants } from "../utils";
// only for tab completion // userId, username is stored in appContext
const preview = { const preview = {
id: Constants.LOADING,
avatar: "",
username: Constants.LOADING,
email: Constants.LOADING, email: Constants.LOADING,
sessions: [], sessions: [],
apiKeys: [], apiKeys: [],
}; };
const UserProfileContext = createContext({ userProfile: preview }); const UserProfileContext = createContext(preview);
export const useUserProfileContext = () => useContext(UserProfileContext); export const useUserProfileContext = () => useContext(UserProfileContext);
export function UserProfileProvider({ children }) { export function UserProfileProvider({ children }) {
const [userProfile, setUserProfile] = useState(preview); const [email, setEmail] = useState("");
const [sessions, setSessions] = useState([]);
const [apiKeys, setApiKeys] = useState([]);
return ( return (
<UserProfileContext.Provider value={{ userProfile, setUserProfile }}> <UserProfileContext.Provider
value={{
email,
setEmail,
sessions,
setSessions,
apiKeys,
setApiKeys,
}}
>
{children} {children}
</UserProfileContext.Provider> </UserProfileContext.Provider>
); );

View File

@ -1,8 +1,14 @@
import { createContext, useContext, useEffect, useRef, useState } from "react"; import { createContext, useContext, useEffect, useRef } from "react";
import { Constants, ReceivedMessagesCommands, myFetch } from "../utils"; import { Constants, myFetch } from "../utils";
import { useSideBarContext } from "./SideBarContext"; import { useSideBarContext } from "./SideBarContext";
import { useAppContext } from "./AppContext"; import { useAppContext } from "./AppContext";
import { message } from "antd"; import { message } from "antd";
import { handleWebSocketMessage } from "../Handlers/WebSocketMessageHandler";
import { useGroupTasksContext } from "./GroupTasksContext";
import { useNavigate } from "react-router-dom";
import { useUserProfileContext } from "./UserProfileContext";
import { useAdminAreaRolesContext } from "./AdminAreaRolesContext";
import { useUsersContext } from "./UsersContext";
const WebSocketContext = createContext(null); const WebSocketContext = createContext(null);
@ -14,10 +20,16 @@ export default function WebSocketProvider({
setUserSession, setUserSession,
isWebSocketReady, isWebSocketReady,
setIsWebSocketReady, setIsWebSocketReady,
notificationApi,
}) { }) {
const ws = useRef(null); const ws = useRef(null);
const navigate = useNavigate();
const appContext = useAppContext(); const appContext = useAppContext();
const sideBarContext = useSideBarContext(); const sideBarContext = useSideBarContext();
const groupTasksContext = useGroupTasksContext();
const userProfileContext = useUserProfileContext();
const adminAreaRolesContext = useAdminAreaRolesContext();
const usersContext = useUsersContext();
const connect = () => { const connect = () => {
ws.current = new WebSocket(`${Constants.WS_ADDRESS}?auth=${userSession}`); ws.current = new WebSocket(`${Constants.WS_ADDRESS}?auth=${userSession}`);
@ -28,27 +40,29 @@ export default function WebSocketProvider({
setIsWebSocketReady(true); setIsWebSocketReady(true);
myFetch("/user/", "GET").then((data) => { myFetch("/user/", "GET").then((data) => {
console.log("user info", data); appContext.userId.current = data.UserId;
appContext.setUserPermissions(
appContext.setUsername(data.Username); data.Permissions === null ? [] : data.Permissions
appContext.setAvatar(data.Avatar); );
appContext.setUserPermissions(data.Permissions); appContext.setUsers(data.Users);
appContext.setAvailableGroupTasks(data.AvailableGroupTasks); sideBarContext.setUsername(data.Username);
sideBarContext.setAvatar(data.Avatar);
sideBarContext.setAvailableGroupTasks(data.AvailableGroupTasks);
}); });
}; };
ws.current.onmessage = (event) => { ws.current.onmessage = (event) => {
const data = JSON.parse(event.data); handleWebSocketMessage(
console.log("received message", data); event,
navigate,
const cmd = data.Cmd; notificationApi,
const body = data.Body; sideBarContext,
appContext,
switch (cmd) { groupTasksContext,
case ReceivedMessagesCommands.UpdateConnectedUsers: userProfileContext,
sideBarContext.setConnectedUsers(body.WebSocketUsersCount); adminAreaRolesContext,
break; usersContext
} );
}; };
ws.current.onclose = (event) => { ws.current.onclose = (event) => {

View File

@ -1 +1,987 @@
export function handleWebSocketMessage(message) {} import {
Constants,
GroupTasksStepsLockedAndUserUpdateInputValueRememberId,
} from "../utils";
// commands received from the backend server
export const ReceivedMessagesCommands = {
InitUserSocketConnection: 1,
UpdateConnectedUsers: 2,
NewGroupTaskStarted: 3,
NewGroupTaskStep: 4,
UpdateGroupTaskStep: 5,
UpdateGroupTask: 6,
ReloadingGroupTasks: 7,
GroupTasksReloaded: 8,
UpdateUserSessions: 9,
UpdateAllUsersUserAvatar: 10,
NewScanner: 11,
DeleteScanner: 12,
UpdateScannerUsedByUserId: 13,
ScanResult: 14,
UpdateScannerLastUsed: 15,
TaskLocked: 16,
TaskUnlocked: 17,
UserProfileUpdated: 18,
AdminAreaNewRoleCreated: 19,
AdminAreaRoleUpdated: 20,
AdminAreaUpdateRoleSortingOrder: 21,
AdminAreaRoleDeleted: 22,
AllUsersUserRoleUpdated: 23,
RolePermissionsUpdated: 24,
ErrorNoPermissions: 25,
AllUsersNewUserCreated: 26,
AllUsersUserDeleted: 27,
AllUsersUserDeactivation: 28,
GroupTasksCategoryGroupChanges: 29,
NewUserApiKeyCreated: 30,
DeletedUserApiKey: 31,
NewApiKeyUsageCount: 32,
InstallingPythonPackages: 33,
InstallingPythonPackagesFailed: 34,
InstallingPythonPackagesFinished: 35,
InstallingGlobalPythonPackages: 36,
InstallingGlobalPythonPackagesFailed: 37,
InstallingGlobalPythonPackagesFinished: 38,
};
// commands sent to the backend server
export const SentMessagesCommands = {
StartGroupTasks: 1,
TaskFailedTryAgainRunTaskStep: 2,
TaskContinueTaskStep: 3,
ReloadGroupTasks: 4,
TaskLocking: 5,
UpdateUserProfile: 6,
AdminAreaCreateNewRole: 7,
AdminAreaUpdateRole: 8,
AdminAreaUpdateRoleSortingOrder: 9,
AdminAreaDeleteRole: 10,
AllUsersUpdateUserRole: 11,
AllUsersCreateNewUser: 12,
AllUsersDeleteUser: 13,
AllUsersUserDeactivation: 14,
ScannersUseScanners: 15,
ScannersDisconnectScanner: 16,
GroupTasksCheckingForCategoryGroupChanges: 17,
HandleUserActionTaskStep: 18,
CreateNewUserApiKey: 19,
DeleteUserApiKey: 20,
GroupTasksInstallPythonPackages: 21,
GroupTasksInstallGlobalPythonPackages: 22,
};
export function handleWebSocketMessage(
event,
navigate,
notificationApi,
sideBarContext,
appContext,
groupTasksContext,
userProfileContext,
adminAreaRolesContext,
usersContext
) {
const data = JSON.parse(event.data);
const cmd = data.Cmd;
const body = data.Body;
switch (cmd) {
case ReceivedMessagesCommands.UpdateConnectedUsers:
sideBarContext.setConnectedUsers(body.WebSocketUsersCount);
usersContext.setUsers((arr) => {
const newArr = [...arr];
const arrIndex = arr.findIndex((arr1) => arr1.Id === body.UserId);
if (arrIndex !== -1) {
newArr[arrIndex].ConnectionStatus = body.ConnectionStatus;
newArr[arrIndex].LastOnline = body.LastOnline;
}
return newArr;
});
break;
case ReceivedMessagesCommands.NewGroupTaskStarted:
groupTasksContext.setGroupTasks((arr) => [...arr, body]);
if (
body.RememberId ===
groupTasksContext.startGroupTasksOpenModalRememberIdRef.current
) {
navigate(`${Constants.ROUTE_PATHS.GROUP_TASKS}/${body.Id}`);
}
break;
case ReceivedMessagesCommands.NewGroupTaskStep:
groupTasksContext.setGroupTasksSteps((arr) => [...arr, body]);
scrollToNextStep(body.GroupTasksId, body.Step);
break;
case ReceivedMessagesCommands.UpdateGroupTaskStep:
groupTasksContext.setGroupTasksSteps((arr) => {
const newArr = [...arr];
const stepIndex = arr.findIndex((arr1) => arr1.Id === body.Id);
if (stepIndex !== -1) {
newArr[stepIndex] = body;
}
return newArr;
});
scrollToNextStep(body.GroupTasksId, body.Step);
break;
case ReceivedMessagesCommands.UpdateGroupTask:
groupTasksContext.setGroupTasks((arr) => {
const newArr = [...arr];
const groupTaskIndex = arr.findIndex((arr1) => arr1.Id === body.Id);
if (groupTaskIndex !== -1) {
newArr[groupTaskIndex] = body;
}
return newArr;
});
break;
case ReceivedMessagesCommands.ReloadingGroupTasks:
notificationApi["warning"]({
message: `Group ${body} is reloading`,
duration: 2,
});
break;
case ReceivedMessagesCommands.GroupTasksReloaded:
if (body.RemovedCategory !== undefined) {
groupTasksContext.setCategoryGroups((arr) =>
arr.filter((arr1) => arr1.category !== body.RemovedCategory)
);
appContext.setUserPermissions((arr) =>
arr.filter((arr1) => arr1 !== body.RemovedCategory)
);
/*setUser((user) => {
const updatedUser = { ...user };
updatedUser.Permissions = updatedUser.Permissions.filter(
(arr) => !body.RemovedPermissions.includes(arr)
);
return updatedUser;
}); */
/*
setAdminAreaRolesPermissions((arr) => {
const newArr = [...arr];
newArr.forEach((role, i) => {
if (role.Permissions !== null) {
newArr[i].Permissions = role.Permissions.filter(
(arr) => !body.RemovedPermissions.includes(arr)
);
}
});
return newArr;
}); */
notificationApi["info"]({
message: `Category ${body.RemovedCategory} was removed`,
duration: 2,
});
break;
}
groupTasksContext.setCategoryGroups((arr) => {
const newArr = [...arr];
const categoryIndex = arr.findIndex(
(arr1) => arr1.category === body.Category
);
if (categoryIndex !== -1) {
newArr[categoryIndex].groups = body.CategoryGroups;
}
return newArr;
});
break;
case ReceivedMessagesCommands.UpdateUserSessions:
//setUser((arr) => ({ ...arr, Sessions: body }));
//userProfileContext.setUserProfile((arr) => ({ ...arr, Sessions: body }));
userProfileContext.setSessions(body);
break;
case ReceivedMessagesCommands.UpdateAllUsersUserAvatar:
/*setAllUsers((arr) => {
const newArr = [...arr];
newArr[arr.findIndex((arr1) => arr1.Id === body.UserId)].Avatar =
body.Avatar;
return newArr;
});*/
if (appContext.userId.current === body.UserId) {
sideBarContext.setAvatar(body.Avatar);
/*
userProfileContext.setUserProfile((user) => ({
...user,
avatar: body.Avatar,
})); */
}
usersContext.setUsers((arr) => {
const newArr = [...arr];
const arrIndex = arr.findIndex((arr1) => arr1.Id === body.UserId);
if (arrIndex !== -1) {
newArr[arrIndex].Avatar = body.Avatar;
}
return newArr;
});
/*
appContext.setUsers((arr) => {
const newArr = [...arr];
newArr[arr.findIndex((arr1) => arr1.Id === body.UserId)].Avatar =
body.Avatar;
return newArr;
}); */
break;
/*case ReceivedMessagesCommands.NewScanner:
setScanners((arr) => [...arr, body]);
break;
case ReceivedMessagesCommands.DeleteScanner:
setScanners((arr) => arr.filter((arr) => arr.Id !== body.Id));
break; */
/*case ReceivedMessagesCommands.UpdateScannerUsedByUserId:
setScanners((arr) => {
const newArr = [...arr];
newArr[
arr.findIndex((arr1) => arr1.Id === body.ScannerId)
].UsedByUserId = body.UsedByUserId;
return newArr;
});
break;*/
/* case ReceivedMessagesCommands.ScanResult:
const decodedScanResult = DecodedBase64ToString(body);
if (decodedScanResult === "" || decodedScanResult === null) {
notificationApi["error"]({
message: `Failed to decode scan result`,
description: "See in developer console",
});
console.error(
"Received scan result: ",
body,
"Decoded result: ",
decodedScanResult
);
break;
}
notificationApi["info"]({
message: `Scan Result`,
description: decodedScanResult,
});
new Audio(
`${Constants.STATIC_CONTENT_ADDRESS}sounds/scan_result.mp3`
).play();
break;
case ReceivedMessagesCommands.UpdateScannerLastUsed:
setScanners((arr) => {
const newArr = [...arr];
newArr[arr.findIndex((arr1) => arr1.Id === body.ScannerId)].LastUsed =
body.LastUsed;
return newArr;
});
break;*/
case ReceivedMessagesCommands.TaskLocked:
if (
body.rememberId ===
GroupTasksStepsLockedAndUserUpdateInputValueRememberId
)
break;
groupTasksContext.setGroupTasksSteps((arr) => {
const newArr = [...arr];
const stepIndex = arr.findIndex(
(arr1) =>
arr1.GroupTasksId === body.GroupTaskId && arr1.Step === body.Step
);
if (stepIndex !== -1) {
newArr[stepIndex].LockedByUserId = body.LockedByUserId;
}
return newArr;
});
// update input value
// html based DOM manipulation
const foundInput = document.getElementById(body.element);
if (foundInput) {
// this timeout is needed because the previous useState for the lockedByUserId takes some milliseconds to complete
setTimeout(() => setNativeValue(foundInput, body.value), 50);
}
// update group task step as html based DOM manipulation only works if user has no other modal open
groupTasksContext.setGroupTasksSteps((arr) => {
const newArr = [...arr];
const stepIndex = arr.findIndex(
(arr1) =>
arr1.GroupTasksId === body.groupTaskId && arr1.Step === body.step
);
if (stepIndex === -1) return newArr;
let inputs = [];
if (newArr[stepIndex].Inputs !== "") {
inputs = JSON.parse(newArr[stepIndex].Inputs);
}
let parameterFound = false;
for (let i = 0; i < inputs.length; i++) {
if (inputs[i].parameterName === body.parameterName) {
inputs[i].value = body.value;
parameterFound = true;
break;
}
}
if (!parameterFound) {
let obj = {};
obj["parameterName"] = body.parameterName;
obj["value"] = body.value;
inputs.push(obj);
}
newArr[stepIndex].Inputs = JSON.stringify(inputs);
return newArr;
});
break;
case ReceivedMessagesCommands.TaskUnlocked:
if (
body.rememberId ===
GroupTasksStepsLockedAndUserUpdateInputValueRememberId
)
break;
groupTasksContext.setGroupTasksSteps((arr) => {
const newArr = [...arr];
const stepIndex = arr.findIndex(
(arr1) =>
arr1.GroupTasksId === body.GroupTaskId && arr1.Step === body.Step
);
if (stepIndex !== -1) {
newArr[stepIndex].LockedByUserId = "";
}
return newArr;
});
break;
case ReceivedMessagesCommands.UserProfileUpdated:
// feedback message for the user who has changed his profile
if (body.Result !== undefined) {
if (body.Result === 0) {
notificationApi["error"]({
message: `Profile couldn't be updated`,
description: "Username already in use",
});
} else if (body.Result === 1) {
notificationApi["error"]({
message: `Profile couldn't be updated`,
description: "Email already in use",
});
} else if (body.Result === 2) {
notificationApi["error"]({
message: `Profile couldn't be updated`,
description: "Provided password is incorrect",
});
}
}
if (body.Changes !== undefined) {
if (body.Changes.Username !== undefined) {
if (appContext.userId.current === body.UserId) {
sideBarContext.setUsername(body.Changes.Username);
}
usersContext.setUsers((arr) => {
const newArr = [...arr];
const arrIndex = arr.findIndex((user) => user.Id === body.UserId);
if (arrIndex !== -1) {
newArr[arrIndex].Username = body.Changes.Username;
}
return newArr;
});
}
if (body.Changes.Email !== undefined) {
userProfileContext.setEmail(body.Changes.Email);
}
}
break;
case ReceivedMessagesCommands.AdminAreaNewRoleCreated:
adminAreaRolesContext.setRoles((arr) => [...arr, body]);
adminAreaRolesContext.setRolesPermissions((arr) => [
...arr,
{ RoleId: body.Id, Permissions: [] },
]);
break;
case ReceivedMessagesCommands.AdminAreaRoleUpdated:
adminAreaRolesContext.setRoles((arr) => {
const newArr = [...arr];
const arrIndex = arr.findIndex((arr1) => arr1.Id === body.RoleId);
if (arrIndex !== -1) {
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
) {
adminAreaRolesContext.setRolesPermissions((arr) => {
const newArr = [...arr];
const roleIndex = arr.findIndex(
(item) => item.RoleId === body.RoleId
);
if (roleIndex !== -1) {
if (body.Changes.AddedPermissions !== undefined) {
if (newArr[roleIndex].Permissions === null) {
newArr[roleIndex].Permissions = body.Changes.AddedPermissions;
} else {
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)
);
}
}
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;
case ReceivedMessagesCommands.AdminAreaUpdateRoleSortingOrder:
adminAreaRolesContext.setRoles((arr) => {
const newArr = [...arr];
const updatedRoleIndex = newArr.findIndex(
(role) => role.Id === body.RoleId
);
if (updatedRoleIndex === -1) return newArr;
const currentSortingOrder = newArr[updatedRoleIndex].SortingOrder;
if (body.Direction === 0) {
newArr[updatedRoleIndex].SortingOrder =
newArr[updatedRoleIndex].SortingOrder - 1;
} else {
newArr[updatedRoleIndex].SortingOrder =
newArr[updatedRoleIndex].SortingOrder + 1;
}
const newSortingOrder = newArr[updatedRoleIndex].SortingOrder;
for (let i = 0; i < newArr.length; i++) {
if (newArr[i].Id !== newArr[updatedRoleIndex].Id) {
if (newArr[i].SortingOrder === newSortingOrder) {
newArr[i].SortingOrder = currentSortingOrder;
} else if (
newArr[i].SortingOrder < currentSortingOrder &&
newArr[i].SortingOrder >= newSortingOrder
) {
newArr[i].SortingOrder = newArr[i].SortingOrder + 1;
} else if (
newArr[i].SortingOrder > currentSortingOrder &&
newArr[i].SortingOrder <= newSortingOrder
) {
newArr[i].SortingOrder = newArr[i] - 1;
}
}
}
newArr.sort((a, b) => a.SortingOrder - b.SortingOrder);
return newArr;
});
break;
case ReceivedMessagesCommands.AdminAreaRoleDeleted:
adminAreaRolesContext.setRoles((arr) => {
let newArr = [...arr];
const deletedRole = newArr.find((r) => r.Id === body.RoleId);
newArr = newArr.filter((role) => role.Id !== body.RoleId);
for (let i = 0; i < newArr.length; i++) {
if (newArr[i].SortingOrder > deletedRole.SortingOrder) {
newArr[i].SortingOrder = newArr[i].SortingOrder - 1;
}
}
return newArr;
});
adminAreaRolesContext.setRolesPermissions((arr) => {
let newArr = [...arr];
newArr = newArr.filter(
(rolePermission) => rolePermission.RoleId !== body.RoleId
);
return newArr;
});
break;
case ReceivedMessagesCommands.AllUsersUserRoleUpdated:
usersContext.setUsers((arr) => {
const newArr = [...arr];
const arrIndex = arr.findIndex((user) => user.Id === body.UserId);
if (arrIndex !== -1) {
newArr[arrIndex].RoleId = body.RoleId;
}
return newArr;
});
if (body.Permissions !== undefined) {
appContext.setUserPermissions(() =>
body.Permissions === null ? [] : body.Permissions
);
/*setUser((user) => {
const updatedUser = { ...user };
if (body.Permissions === null) {
updatedUser.Permissions = [];
} else {
updatedUser.Permissions = body.Permissions;
}
return updatedUser;
}); */
}
break;
case ReceivedMessagesCommands.RolePermissionsUpdated:
if (
body.AddedPermissions !== undefined ||
body.RemovedPermissions !== undefined
) {
appContext.setUserPermissions((arr) => {
let newArr = [...arr];
if (body.AddedPermissions !== undefined) {
newArr = newArr.concat(body.AddedPermissions);
}
if (body.RemovedPermissions !== undefined) {
newArr = newArr.filter(
(permission) => !body.RemovedPermissions.includes(permission)
);
}
return newArr;
});
/*setUser((user) => {
const updatedUser = { ...user };
if (body.AddedPermissions !== undefined) {
updatedUser.Permissions = updatedUser.Permissions.concat(
body.AddedPermissions
);
}
if (body.RemovedPermissions !== undefined) {
updatedUser.Permissions = updatedUser.Permissions.filter(
(permission) => !body.RemovedPermissions.includes(permission)
);
}
return updatedUser;
});*/
}
break;
case ReceivedMessagesCommands.ErrorNoPermissions:
notificationApi["error"]({
message: `No permissions`,
description: `Please contact the administrator`,
});
break;
case ReceivedMessagesCommands.AllUsersNewUserCreated:
if (body.Result !== undefined) {
if (body.Result === 0) {
notificationApi["error"]({
message: `User could not be created`,
description: `Username already in use`,
});
}
if (body.Result === 1) {
notificationApi["error"]({
message: `User could not be created`,
description: `Email already in use`,
});
}
break;
}
usersContext.setUsers((arr) => [
...arr,
{
Id: body.Id,
RoleId: body.RoleId,
Username: body.Username,
ConnectionStatus: body.ConnectionStatus,
Deactivated: body.Deactivated,
},
]);
break;
case ReceivedMessagesCommands.AllUsersUserDeleted:
usersContext.setUsers((arr) => {
let newArr = [...arr];
newArr = newArr.filter((user) => user.Id !== body.UserId);
return newArr;
});
/*
if (body.ScannerId !== "") {
setScanners((arr) => {
let newArr = [...arr];
newArr[
newArr.findIndex((scanner) => scanner.Id === body.ScannerId)
].UsedByUserId = "";
return newArr;
});
} */
break;
case ReceivedMessagesCommands.AllUsersUserDeactivation:
usersContext.setUsers((arr) => {
let newArr = [...arr];
const arrIndex = newArr.findIndex((user) => user.Id === body.UserId);
if (arrIndex !== -1) {
newArr[arrIndex].Deactivated = body.Deactivated;
}
return newArr;
});
break;
case ReceivedMessagesCommands.GroupTasksCategoryGroupChanges:
if (
body["AddedPermissions"] !== undefined ||
body["RemovedPermissions"] !== undefined
) {
appContext.setUserPermissions((arr) => {
let newArr = [...arr];
if (body["AddedPermissions"] !== undefined) {
newArr = newArr.concat(body.AddedPermissions);
}
if (body["RemovedPermissions"] !== undefined) {
newArr = newArr.filter(
(permission) => !body.RemovedPermissions.includes(permission)
);
}
return newArr;
});
/*setUser((user) => {
const updatedUser = { ...user };
if (
body.AddedPermissions !== undefined &&
updatedUser.RoleId === body.MasterRoleId
) {
updatedUser.Permissions = updatedUser.Permissions.concat(
body.AddedPermissions
);
}
if (body.RemovedPermissions !== undefined) {
updatedUser.Permissions = updatedUser.Permissions.filter(
(permission) => !body.RemovedPermissions.includes(permission)
);
}
return updatedUser;
});*/
adminAreaRolesContext.setRolesPermissions((arr) => {
let newArr = [...arr];
const roleIndex = arr.findIndex(
(item) => item.RoleId === body.MasterRoleId
);
if (roleIndex !== -1) {
if (body.AddedPermissions !== undefined) {
newArr[roleIndex].Permissions = newArr[
roleIndex
].Permissions.concat(body.AddedPermissions);
}
if (body.RemovedPermissions !== undefined) {
newArr[roleIndex].Permissions = newArr[
roleIndex
].Permissions.filter(
(permission) => !body.RemovedPermissions.includes(permission)
);
}
}
return newArr;
});
}
if (
body["AddedCategoryGroups"] !== undefined ||
body["RemovedCategoryGroups"] !== undefined
) {
groupTasksContext.setCategoryGroups((arr) => {
let newArr = [...arr];
if (body["RemovedCategoryGroups"] !== undefined) {
newArr = newArr.filter(
(c) => !body.RemovedCategoryGroups.includes(c.category)
);
}
if (body["AddedCategoryGroups"] !== undefined) {
newArr = newArr.concat(body.AddedCategoryGroups);
}
newArr = newArr.sort((a, b) => {
if (a.category < b.category) {
return -1; // a below b
} else if (a.category > b.category) {
return 1; // a above b
} else {
return 0; // keep the order
}
});
return newArr;
});
}
break;
case ReceivedMessagesCommands.NewUserApiKeyCreated:
/*userProfileContext.setUserProfile((user) => ({
...user,
ApiKeys: [...user.ApiKeys, body],
})); */
userProfileContext.setApiKeys((arr) => [...arr, body]);
/*setUser((user) => {
const updatedUser = { ...user };
updatedUser.ApiKeys.push(body);
return updatedUser;
});*/
break;
case ReceivedMessagesCommands.DeletedUserApiKey:
/*userProfileContext.setUserProfile((user) => ({
...user,
ApiKeys: user.ApiKeys.filter((apiKey) => apiKey.Id !== body),
})); */
userProfileContext.setApiKeys((arr) =>
arr.filter((apiKey) => apiKey.Id !== body)
);
/*setUser((user) => {
const updatedUser = { ...user };
updatedUser.ApiKeys = updatedUser.ApiKeys.filter(
(apiKey) => apiKey.Id !== body
);
return updatedUser;
}); */
break;
case ReceivedMessagesCommands.NewApiKeyUsageCount:
userProfileContext.setApiKeys((arr) => {
const newArr = [...arr];
const arrIndex = newArr.findIndex((apiKey) => apiKey.Id === body.Id);
if (arrIndex !== -1) {
newArr[arrIndex].UsageCount = body.UsageCount;
newArr[arrIndex].LastUsed = body.LastUsed;
}
return newArr;
});
/*userProfileContext.setUserProfile((user) => {
const updatedUser = { ...user };
const arrIndex = updatedUser.ApiKeys.findIndex(
(apiKey) => apiKey.Id === body.Id
);
if (arrIndex !== -1) {
updatedUser.ApiKeys[arrIndex].UsageCount = body.UsageCount;
updatedUser.ApiKeys[arrIndex].LastUsed = body.LastUsed;
}
return updatedUser;
}); */
/*setUser((user) => {
const updatedUser = { ...user };
const arrIndex = updatedUser.ApiKeys.findIndex(
(apiKey) => apiKey.Id === body.Id
);
if (arrIndex !== -1) {
updatedUser.ApiKeys[arrIndex].UsageCount = body.UsageCount;
updatedUser.ApiKeys[arrIndex].LastUsed = body.LastUsed;
}
return updatedUser;
}); */
break;
case ReceivedMessagesCommands.InstallingPythonPackages:
notificationApi["info"]({
message: `Installing python packages for ${body.GroupId} of ${body.Category}`,
description: `This may take a while`,
});
break;
case ReceivedMessagesCommands.InstallingPythonPackagesFailed:
notificationApi["error"]({
message: `Installing python packages for ${body.GroupId} of ${body.Category} failed`,
description: `Please check the logs`,
});
break;
case ReceivedMessagesCommands.InstallingPythonPackagesFinished:
notificationApi["success"]({
message: `Installing python packages for ${body.GroupId} of ${body.Category} finished`,
description: `You can now start the group task`,
});
break;
case ReceivedMessagesCommands.InstallingGlobalPythonPackages:
notificationApi["info"]({
message: `Installing global python packages`,
description: `This may take a while`,
});
break;
case ReceivedMessagesCommands.InstallingGlobalPythonPackagesFailed:
notificationApi["error"]({
message: `Installing global python packages failed`,
description: `Please check the logs`,
});
break;
case ReceivedMessagesCommands.InstallingGlobalPythonPackagesFinished:
notificationApi["success"]({
message: `Installing global python packages finished`,
description: `You can now continue with the work`,
});
break;
default:
console.error("unknown command", cmd);
break;
}
}
function scrollToNextStep(groupTaskId, step) {
setTimeout(
() =>
document
.getElementById(`${groupTaskId}-scroll-${step - 1}`)
?.scrollIntoView({ behavior: "smooth" }),
200
);
}
// https://stackoverflow.com/a/52486921
function setNativeValue(element, value) {
let lastValue = element.value;
element.value = value;
let event = new Event("input", { target: element, bubbles: true });
// React 15
event.simulated = true;
// React 16
let tracker = element._valueTracker;
if (tracker) {
tracker.setValue(lastValue);
}
element.dispatchEvent(event);
}

View File

@ -15,8 +15,8 @@ import {
import { import {
Constants, Constants,
SentMessagesCommands, SentMessagesCommands,
WebSocketContext,
hasPermission, hasPermission,
myFetch,
} from "../../../utils"; } from "../../../utils";
import { import {
ArrowDownOutlined, ArrowDownOutlined,
@ -28,15 +28,20 @@ import {
QuestionCircleOutlined, QuestionCircleOutlined,
SaveOutlined, SaveOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import { useContext, useState } from "react"; import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { MyAvatar } from "../../../Components/MyAvatar"; import { MyAvatar } from "../../../Components/MyAvatar";
import { useAdminAreaRolesContext } from "../../../Contexts/AdminAreaRolesContext";
import { useWebSocketContext } from "../../../Contexts/WebSocketContext";
import { useAppContext } from "../../../Contexts/AppContext";
const { useBreakpoint } = Grid; const { useBreakpoint } = Grid;
export default function AdminAreaRoles() { export default function AdminAreaRoles() {
const { t } = useTranslation(); const { t } = useTranslation();
const webSocketContext = useContext(WebSocketContext); const webSocketContext = useWebSocketContext();
const appContext = useAppContext();
const adminAreaRolesContext = useAdminAreaRolesContext();
const [notificationApi, notificationContextHolder] = const [notificationApi, notificationContextHolder] =
notification.useNotification(); notification.useNotification();
@ -97,7 +102,9 @@ export default function AdminAreaRoles() {
}; };
const getRolePermissions = (role) => { const getRolePermissions = (role) => {
const rolePermissions = webSocketContext.AdminAreaRolesPermissions.find( if (role === undefined) return [];
const rolePermissions = adminAreaRolesContext.rolesPermissions.find(
(r) => r.RoleId === role.Id (r) => r.RoleId === role.Id
); );
@ -110,25 +117,34 @@ export default function AdminAreaRoles() {
const treeData = createTreeDataList( const treeData = createTreeDataList(
getRolePermissions( getRolePermissions(
webSocketContext.AllRoles.find((role) => role.Master === true) adminAreaRolesContext.roles.find((role) => role.Master === true)
) )
); );
useEffect(() => {
myFetch("/adminarea/roles", "GET").then((data) => {
adminAreaRolesContext.setRoles(data.Roles);
adminAreaRolesContext.setRolesPermissions(data.RolesPermissions);
});
}, []);
return ( return (
<Space direction="vertical" style={{ width: "100%" }}> <Space direction="vertical" style={{ width: "100%" }}>
{notificationContextHolder} {notificationContextHolder}
{webSocketContext.AllRoles.map((role) => ( {adminAreaRolesContext.roles.map((role) => (
<Role <Role
key={role.Id} key={role.Id}
treeData={treeData} treeData={treeData}
role={role} role={role}
webSocketContext={webSocketContext} webSocketContext={webSocketContext}
appContext={appContext}
adminAreaRolesContext={adminAreaRolesContext}
notificationApi={notificationApi} notificationApi={notificationApi}
/> />
))} ))}
{hasPermission( {hasPermission(
webSocketContext.User.Permissions, appContext.userPermissions,
Constants.PERMISSIONS.ADMIN_AREA.ROLES.CREATE_NEW_ROLE Constants.PERMISSIONS.ADMIN_AREA.ROLES.CREATE_NEW_ROLE
) && ( ) && (
<div <div
@ -154,7 +170,14 @@ export default function AdminAreaRoles() {
); );
} }
function Role({ treeData, role, webSocketContext, notificationApi }) { function Role({
treeData,
role,
webSocketContext,
appContext,
adminAreaRolesContext,
notificationApi,
}) {
const { t } = useTranslation(); const { t } = useTranslation();
const [editMode, setEditMode] = useState(false); const [editMode, setEditMode] = useState(false);
const [roleDisplayName, setRoleDisplayName] = useState(""); const [roleDisplayName, setRoleDisplayName] = useState("");
@ -162,7 +185,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) {
const screenBreakpoint = useBreakpoint(); const screenBreakpoint = useBreakpoint();
const getRolePermissions = (role) => { const getRolePermissions = (role) => {
const rolePermissions = webSocketContext.AdminAreaRolesPermissions.find( const rolePermissions = adminAreaRolesContext.rolesPermissions.find(
(r) => r.RoleId === role.Id (r) => r.RoleId === role.Id
); );
@ -182,10 +205,10 @@ function Role({ treeData, role, webSocketContext, notificationApi }) {
setCheckedTreeKeyPermissions(checkedKeys); setCheckedTreeKeyPermissions(checkedKeys);
const getMasterPermissions = () => { const getMasterPermissions = () => {
return webSocketContext.AdminAreaRolesPermissions.find( return adminAreaRolesContext.rolesPermissions.find(
(role) => (role) =>
role.RoleId === role.RoleId ===
webSocketContext.AllRoles.find((role) => role.Master === true).Id adminAreaRolesContext.roles.find((role) => role.Master === true).Id
).Permissions; ).Permissions;
}; };
@ -335,7 +358,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) {
}; };
const getUsersInRole = () => { const getUsersInRole = () => {
return webSocketContext.AllUsers.filter((user) => user.RoleId === role.Id); return appContext.users.filter((user) => user.RoleId === role.Id);
}; };
const UserAvatarsInRole = () => { const UserAvatarsInRole = () => {
@ -378,7 +401,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) {
}; };
const getMaxRoleSortingOrder = () => { const getMaxRoleSortingOrder = () => {
return webSocketContext.AllRoles[webSocketContext.AllRoles.length - 1] return adminAreaRolesContext.roles[adminAreaRolesContext.roles.length - 1]
.SortingOrder; .SortingOrder;
}; };
@ -392,7 +415,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) {
extra: editMode ? ( extra: editMode ? (
<Space key="spaceedit" style={{ paddingLeft: 10 }}> <Space key="spaceedit" style={{ paddingLeft: 10 }}>
{hasPermission( {hasPermission(
webSocketContext.User.Permissions, appContext.userPermissions,
Constants.PERMISSIONS.ADMIN_AREA.ROLES.DELETE_ROLE Constants.PERMISSIONS.ADMIN_AREA.ROLES.DELETE_ROLE
) && ( ) && (
<> <>
@ -422,7 +445,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) {
)} )}
{hasPermission( {hasPermission(
webSocketContext.User.Permissions, appContext.userPermissions,
Constants.PERMISSIONS.ADMIN_AREA.ROLES.MOVE_ROLE_UP_DOWN Constants.PERMISSIONS.ADMIN_AREA.ROLES.MOVE_ROLE_UP_DOWN
) && ( ) && (
<> <>
@ -454,7 +477,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) {
)} )}
{hasPermission( {hasPermission(
webSocketContext.User.Permissions, appContext.userPermissions,
Constants.PERMISSIONS.ADMIN_AREA.ROLES.UPDATE_ROLE Constants.PERMISSIONS.ADMIN_AREA.ROLES.UPDATE_ROLE
) && ( ) && (
<Tooltip title={t("adminArea.save.tooltip.title")}> <Tooltip title={t("adminArea.save.tooltip.title")}>

View File

@ -4,14 +4,16 @@ import {
Constants, Constants,
EncodeStringToBase64, EncodeStringToBase64,
SentMessagesCommands, SentMessagesCommands,
WebSocketContext,
isEmailValid, isEmailValid,
} from "../../utils"; } from "../../utils";
import { useContext, useState } from "react"; import { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useWebSocketContext } from "../../Contexts/WebSocketContext";
import { useUsersContext } from "../../Contexts/UsersContext";
export default function CreateUserModal({ isModalOpen, setIsModalOpen }) { export default function CreateUserModal({ isModalOpen, setIsModalOpen }) {
const webSocketContext = useContext(WebSocketContext); const webSocketContext = useWebSocketContext();
const usersContext = useUsersContext();
const { t } = useTranslation(); const { t } = useTranslation();
const [username, setUsername] = useState(""); const [username, setUsername] = useState("");
const [email, setEmail] = useState(""); const [email, setEmail] = useState("");
@ -121,7 +123,7 @@ export default function CreateUserModal({ isModalOpen, setIsModalOpen }) {
onChange={(e) => setSelectedRoleId(e)} onChange={(e) => setSelectedRoleId(e)}
placeholder={t("allUsers.createUserModal.form.role.placeholder")} placeholder={t("allUsers.createUserModal.form.role.placeholder")}
> >
{webSocketContext.AllRoles.map((role) => ( {usersContext.roles.map((role) => (
<Select.Option key={role.Id}>{role.DisplayName}</Select.Option> <Select.Option key={role.Id}>{role.DisplayName}</Select.Option>
))} ))}
</Select> </Select>

View File

@ -332,8 +332,6 @@ export default function AllUsers() {
useEffect(() => { useEffect(() => {
myFetch("/users", "GET").then((data) => { myFetch("/users", "GET").then((data) => {
console.log("users", data);
usersContext.setRoleId(data.RoleId); usersContext.setRoleId(data.RoleId);
usersContext.setUsers(data.Users); usersContext.setUsers(data.Users);
usersContext.setRoles(data.Roles); usersContext.setRoles(data.Roles);

View File

@ -1,6 +1,6 @@
import React, { useContext } from "react"; import { memo } from "react";
import { WebSocketContext } from "../../utils";
import { Card, Typography } from "antd"; import { Card, Typography } from "antd";
import { useSideBarContext } from "../../Contexts/SideBarContext";
const randomGreeting = Math.floor(Math.random() * 18); const randomGreeting = Math.floor(Math.random() * 18);
@ -105,13 +105,13 @@ function getGreeting(name) {
return greeting; return greeting;
} }
const Dashboard = React.memo(() => { const Dashboard = memo(() => {
const webSocketContext = useContext(WebSocketContext); const sideBarContext = useSideBarContext();
return ( return (
<Card> <Card>
<Typography.Title level={4} style={{ margin: 0 }}> <Typography.Title level={4} style={{ margin: 0 }}>
{getGreeting(webSocketContext.User.Username)} {getGreeting(sideBarContext.username)}
</Typography.Title> </Typography.Title>
</Card> </Card>
); );

View File

@ -1,13 +1,7 @@
import { 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 { useEffect, useState } from "react";
import CreateEquipmentDocumentationModal from "./CreateEquipmentDocumentationModal"; import CreateEquipmentDocumentationModal from "./CreateEquipmentDocumentationModal";
import { import { AppStyle, Constants, FormatDatetime, myFetch } from "../../utils";
AppStyle,
Constants,
FormatDatetime,
WebSocketContext,
myFetch,
} from "../../utils";
import { import {
BookOutlined, BookOutlined,
InfoCircleOutlined, InfoCircleOutlined,
@ -17,10 +11,11 @@ import EditEquipmentDocumentationModal from "./EditEquipmentDocumentationModal";
import { NoteComponent } from "."; import { NoteComponent } from ".";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { MyAvatar } from "../../Components/MyAvatar"; import { MyAvatar } from "../../Components/MyAvatar";
import { useAppContext } from "../../Contexts/AppContext";
export default function ViewEquipmentDocumentations({ scannerResult }) { export default function ViewEquipmentDocumentations({ scannerResult }) {
const { t } = useTranslation(); const { t } = useTranslation();
const webSocketContext = useContext(WebSocketContext); const appContext = useAppContext();
console.log("render ViewEquipmentDocumentations"); console.log("render ViewEquipmentDocumentations");
@ -137,7 +132,7 @@ export default function ViewEquipmentDocumentations({ scannerResult }) {
}} }}
> >
<MyAvatar <MyAvatar
allUsers={webSocketContext.AllUsers} allUsers={appContext.users}
userId={documentation.CreatedByUserId} userId={documentation.CreatedByUserId}
tooltip tooltip
/> />

View File

@ -20,13 +20,13 @@ import {
FormatDatetime, FormatDatetime,
GetDuration, GetDuration,
SentMessagesCommands, SentMessagesCommands,
WebSocketContext,
hasOneXYPermission, hasOneXYPermission,
hasXYPermission, hasXYPermission,
} from "../../../utils"; } from "../../../utils";
import { useContext } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { MyAvatar } from "../../../Components/MyAvatar"; import { MyAvatar } from "../../../Components/MyAvatar";
import { useWebSocketContext } from "../../../Contexts/WebSocketContext";
import { useAppContext } from "../../../Contexts/AppContext";
const { useBreakpoint } = Grid; const { useBreakpoint } = Grid;
@ -35,7 +35,8 @@ export default function GroupTaskTableList({
showGroupTypeSelectionModal, showGroupTypeSelectionModal,
groupTasks, groupTasks,
}) { }) {
const webSocketContext = useContext(WebSocketContext); const webSocketContext = useWebSocketContext();
const appContext = useAppContext();
const { t } = useTranslation(); const { t } = useTranslation();
const screenBreakpoint = useBreakpoint(); const screenBreakpoint = useBreakpoint();
@ -167,7 +168,7 @@ export default function GroupTaskTableList({
groupTasks.forEach((groupTask) => { groupTasks.forEach((groupTask) => {
if (groupTask.Category === categoryGroup.category) { if (groupTask.Category === categoryGroup.category) {
const user = webSocketContext.AllUsers.find( const user = appContext.users.find(
(user) => user.Id === groupTask.CreatorUserId (user) => user.Id === groupTask.CreatorUserId
); );
@ -233,7 +234,7 @@ export default function GroupTaskTableList({
<Divider orientation="left">{categoryGroup.category}</Divider> <Divider orientation="left">{categoryGroup.category}</Divider>
{hasOneXYPermission( {hasOneXYPermission(
webSocketContext.User.Permissions, appContext.userPermissions,
categoryGroup.category, categoryGroup.category,
Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYNewTask, Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYNewTask,
Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYReloadGroupConfig, Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYReloadGroupConfig,
@ -245,7 +246,7 @@ export default function GroupTaskTableList({
}} }}
> >
{hasXYPermission( {hasXYPermission(
webSocketContext.User.Permissions, appContext.userPermissions,
Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYNewTask, Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYNewTask,
categoryGroup.category categoryGroup.category
) && ( ) && (
@ -281,7 +282,7 @@ export default function GroupTaskTableList({
} }
> >
{hasXYPermission( {hasXYPermission(
webSocketContext.User.Permissions, appContext.userPermissions,
Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW
.XYInstallPythonPackages, .XYInstallPythonPackages,
categoryGroup.category categoryGroup.category
@ -310,7 +311,7 @@ export default function GroupTaskTableList({
)} )}
{hasXYPermission( {hasXYPermission(
webSocketContext.User.Permissions, appContext.userPermissions,
Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYReloadGroupConfig, Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYReloadGroupConfig,
categoryGroup.category categoryGroup.category
) && ( ) && (

View File

@ -10,12 +10,11 @@ import {
Tag, Tag,
notification, notification,
} from "antd"; } from "antd";
import { useContext, useRef, useState } from "react"; import { useRef, useState } from "react";
import { useNavigate, useParams } from "react-router-dom"; import { useNavigate, useParams } from "react-router-dom";
import { import {
Constants, Constants,
FormatDatetime, FormatDatetime,
WebSocketContext,
SentMessagesCommands, SentMessagesCommands,
GetDuration, GetDuration,
getUserId, getUserId,
@ -35,9 +34,14 @@ import { useTranslation } from "react-i18next";
import { MyAvatar } from "../../../Components/MyAvatar"; import { MyAvatar } from "../../../Components/MyAvatar";
import MyModal, { MyNotFoundModal } from "../../../Components/MyModal"; import MyModal, { MyNotFoundModal } from "../../../Components/MyModal";
import MyAttachments from "../../../Components/MyAttachments"; import MyAttachments from "../../../Components/MyAttachments";
import { useWebSocketContext } from "../../../Contexts/WebSocketContext";
import { useGroupTasksContext } from "../../../Contexts/GroupTasksContext";
import { useAppContext } from "../../../Contexts/AppContext";
export default function GroupTasksViewModal({ isOpen }) { export default function GroupTasksViewModal({ isOpen }) {
const webSocketContext = useContext(WebSocketContext); const webSocketContext = useWebSocketContext();
const appContext = useAppContext();
const groupTasksContext = useGroupTasksContext();
const navigate = useNavigate(); const navigate = useNavigate();
const [notificationApi, notificationContextHolder] = const [notificationApi, notificationContextHolder] =
notification.useNotification(); notification.useNotification();
@ -47,7 +51,7 @@ export default function GroupTasksViewModal({ isOpen }) {
const handleCancel = () => navigate(Constants.ROUTE_PATHS.GROUP_TASKS); const handleCancel = () => navigate(Constants.ROUTE_PATHS.GROUP_TASKS);
let currentGroupTask; let currentGroupTask;
webSocketContext.GroupTasks.forEach((groupTask) => { groupTasksContext.groupTasks.forEach((groupTask) => {
if (groupTask.Id === paramGroupTaskId) { if (groupTask.Id === paramGroupTaskId) {
currentGroupTask = groupTask; currentGroupTask = groupTask;
} }
@ -57,7 +61,7 @@ export default function GroupTasksViewModal({ isOpen }) {
if ( if (
!currentGroupTask || !currentGroupTask ||
!hasXYPermission( !hasXYPermission(
webSocketContext.User.Permissions, appContext.userPermissions,
Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYView, Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYView,
currentGroupTask.Category currentGroupTask.Category
) )
@ -231,9 +235,9 @@ export default function GroupTasksViewModal({ isOpen }) {
}; };
const ActionHandler = ({ status, taskStepId, index, taskLocked }) => { const ActionHandler = ({ status, taskStepId, index, taskLocked }) => {
const currentStepTask = webSocketContext.CategoryGroups.find( const currentStepTask = groupTasksContext.categoryGroups
(category) => category.category === currentGroupTask.Category .find((category) => category.category === currentGroupTask.Category)
).groups.find((group) => group.id === currentGroupTask.GroupId).tasks[ .groups.find((group) => group.id === currentGroupTask.GroupId).tasks[
index index
]; ];
@ -325,7 +329,7 @@ export default function GroupTasksViewModal({ isOpen }) {
let groupTaskSteps = []; let groupTaskSteps = [];
let groupTasks = []; let groupTasks = [];
webSocketContext.GroupTasksSteps.forEach((step) => { groupTasksContext.groupTasksSteps.forEach((step) => {
if (step.GroupTasksId === paramGroupTaskId) { if (step.GroupTasksId === paramGroupTaskId) {
groupTaskSteps.push(step); groupTaskSteps.push(step);
} }
@ -333,7 +337,7 @@ export default function GroupTasksViewModal({ isOpen }) {
groupTaskSteps.sort((a, b) => a.Step - b.Step); groupTaskSteps.sort((a, b) => a.Step - b.Step);
webSocketContext.CategoryGroups.forEach((categoryGroup) => { groupTasksContext.categoryGroups.forEach((categoryGroup) => {
if (categoryGroup.category === currentGroupTask.Category) { if (categoryGroup.category === currentGroupTask.Category) {
categoryGroup.groups.forEach((group) => { categoryGroup.groups.forEach((group) => {
if (currentGroupTask.GroupId === group.id) { if (currentGroupTask.GroupId === group.id) {
@ -557,7 +561,7 @@ export default function GroupTasksViewModal({ isOpen }) {
<MyModal isOpen={isOpen} onCancel={handleCancel}> <MyModal isOpen={isOpen} onCancel={handleCancel}>
{notificationContextHolder} {notificationContextHolder}
{webSocketContext.GroupTasks.map((groupTask) => { {groupTasksContext.groupTasks.map((groupTask) => {
if (groupTask.Id === paramGroupTaskId) { if (groupTask.Id === paramGroupTaskId) {
let currentGroupTask = groupTask; let currentGroupTask = groupTask;
@ -637,7 +641,8 @@ export default function GroupTasksViewModal({ isOpen }) {
> >
<span style={{ fontWeight: "bold" }}> <span style={{ fontWeight: "bold" }}>
{ {
webSocketContext.CategoryGroups.find( groupTasksContext.categoryGroups
.find(
(categoryGroup) => (categoryGroup) =>
categoryGroup.category === categoryGroup.category ===
currentGroupTask.Category currentGroupTask.Category

View File

@ -10,15 +10,12 @@ import {
Tag, Tag,
notification, notification,
} from "antd"; } from "antd";
import { import { SentMessagesCommands, GetUuid } from "../../../utils";
WebSocketContext,
SentMessagesCommands,
GetUuid,
} from "../../../utils";
import { useContext } from "react";
import { InfoCircleOutlined } from "@ant-design/icons"; import { InfoCircleOutlined } from "@ant-design/icons";
import TextArea from "antd/es/input/TextArea"; import TextArea from "antd/es/input/TextArea";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useWebSocketContext } from "../../../Contexts/WebSocketContext";
import { useGroupTasksContext } from "../../../Contexts/GroupTasksContext";
export default function GroupTypeSelectionModal({ export default function GroupTypeSelectionModal({
isOpen, isOpen,
@ -29,7 +26,8 @@ export default function GroupTypeSelectionModal({
}) { }) {
const [notificationApi, notificationContextHolder] = const [notificationApi, notificationContextHolder] =
notification.useNotification(); notification.useNotification();
const webSocketContext = useContext(WebSocketContext); const webSocketContext = useWebSocketContext();
const groupTasksContext = useGroupTasksContext();
const { t } = useTranslation(); const { t } = useTranslation();
const handleCancel = () => setIsOpen(false); const handleCancel = () => setIsOpen(false);
@ -135,7 +133,8 @@ export default function GroupTypeSelectionModal({
const rememberId = GetUuid(); const rememberId = GetUuid();
webSocketContext.StartGroupTasksOpenModalRememberIdRef.current = rememberId; groupTasksContext.startGroupTasksOpenModalRememberIdRef.current =
rememberId;
webSocketContext.SendSocketMessage(SentMessagesCommands.StartGroupTasks, { webSocketContext.SendSocketMessage(SentMessagesCommands.StartGroupTasks, {
category: categoryGroup.category, category: categoryGroup.category,

View File

@ -1,25 +1,31 @@
import { Button, Col, Popconfirm, Result, Row } from "antd"; import { Button, Col, Popconfirm, Result, Row } from "antd";
import { useContext, useState } from "react"; import { useEffect, useState } from "react";
import GroupTasksViewModal from "./GroupTasksViewModal"; import GroupTasksViewModal from "./GroupTasksViewModal";
import GroupTypeSelectionModal from "./GroupTypeSelectionModal"; import GroupTypeSelectionModal from "./GroupTypeSelectionModal";
import GroupTaskTableList from "./GroupTasksTableList"; import GroupTaskTableList from "./GroupTasksTableList";
import { import {
Constants, Constants,
SentMessagesCommands, SentMessagesCommands,
WebSocketContext,
hasPermission, hasPermission,
hasXYPermission, hasXYPermission,
myFetch,
} from "../../../utils"; } from "../../../utils";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ReloadOutlined } from "@ant-design/icons"; import { ReloadOutlined } from "@ant-design/icons";
import { useGroupTasksContext } from "../../../Contexts/GroupTasksContext";
import { useAppContext } from "../../../Contexts/AppContext";
import { useWebSocketContext } from "../../../Contexts/WebSocketContext";
export default function GroupTasks({ isGroupTasksViewModalOpen }) { export default function GroupTasks({ isGroupTasksViewModalOpen }) {
const webSocketContext = useWebSocketContext();
const appContext = useAppContext();
const groupTasksContext = useGroupTasksContext();
const [isGroupTypeSelectionModalOpen, setIsGroupTypeSelectionModalOpen] = const [isGroupTypeSelectionModalOpen, setIsGroupTypeSelectionModalOpen] =
useState(false); useState(false);
const [currentCategoryGroup, setCurrentCategoryGroup] = useState([]); const [currentCategoryGroup, setCurrentCategoryGroup] = useState([]);
const [currentSelectedModalGroupType, setCurrentSelectedModalGroupType] = const [currentSelectedModalGroupType, setCurrentSelectedModalGroupType] =
useState(); useState();
const webSocketContext = useContext(WebSocketContext);
const { t } = useTranslation(); const { t } = useTranslation();
const showGroupTypeSelectionModal = (categoryGroup) => { const showGroupTypeSelectionModal = (categoryGroup) => {
@ -28,10 +34,10 @@ export default function GroupTasks({ isGroupTasksViewModalOpen }) {
setCurrentSelectedModalGroupType(null); setCurrentSelectedModalGroupType(null);
}; };
const filteredCategoryGroups = webSocketContext.CategoryGroups.filter( const filteredCategoryGroups = groupTasksContext.categoryGroups.filter(
(categoryGroup) => (categoryGroup) =>
hasXYPermission( hasXYPermission(
webSocketContext.User.Permissions, appContext.userPermissions,
Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYView, Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYView,
categoryGroup.category categoryGroup.category
) )
@ -51,9 +57,19 @@ export default function GroupTasks({ isGroupTasksViewModalOpen }) {
); );
}; };
useEffect(() => {
myFetch("/grouptasks", "GET").then((data) => {
console.log("group tasks", data);
groupTasksContext.setCategoryGroups(data.CategoryGroups);
groupTasksContext.setGroupTasks(data.GroupTasks);
groupTasksContext.setGroupTasksSteps(data.GroupTasksSteps);
});
}, []);
return ( return (
<> <>
{webSocketContext.CategoryGroups.length === 0 ? ( {groupTasksContext.categoryGroups.length === 0 ? (
<Result status="404" title={t("groupTasks.categoryGroups.length0")} /> <Result status="404" title={t("groupTasks.categoryGroups.length0")} />
) : ( ) : (
<> <>
@ -66,7 +82,7 @@ export default function GroupTasks({ isGroupTasksViewModalOpen }) {
md={{ span: 8, offset: 16 }} md={{ span: 8, offset: 16 }}
> >
{hasPermission( {hasPermission(
webSocketContext.User.Permissions, appContext.userPermissions,
Constants.PERMISSIONS.GROUP_TASKS Constants.PERMISSIONS.GROUP_TASKS
.INSTALL_GLOBAL_PYTHON_PACKAGES .INSTALL_GLOBAL_PYTHON_PACKAGES
) && ( ) && (
@ -104,7 +120,7 @@ export default function GroupTasks({ isGroupTasksViewModalOpen }) {
key={categoryGroup.category} key={categoryGroup.category}
categoryGroup={categoryGroup} categoryGroup={categoryGroup}
showGroupTypeSelectionModal={showGroupTypeSelectionModal} showGroupTypeSelectionModal={showGroupTypeSelectionModal}
groupTasks={webSocketContext.GroupTasks} groupTasks={groupTasksContext.groupTasks}
/> />
); );
})} })}
@ -131,7 +147,7 @@ export default function GroupTasks({ isGroupTasksViewModalOpen }) {
<GroupTasksViewModal isOpen={isGroupTasksViewModalOpen} /> <GroupTasksViewModal isOpen={isGroupTasksViewModalOpen} />
{hasPermission( {hasPermission(
webSocketContext.User.Permissions, appContext.userPermissions,
Constants.PERMISSIONS.GROUP_TASKS.CHECKING_FOR_CATEGORY_GROUP_CHANGES Constants.PERMISSIONS.GROUP_TASKS.CHECKING_FOR_CATEGORY_GROUP_CHANGES
) && ( ) && (
<div <div

View File

@ -1,18 +1,5 @@
import { Popconfirm, Space, Table, Typography } from "antd";
import {
FormatDatetime,
SentMessagesCommands,
WebSocketContext,
getUserId,
} from "../../utils";
import { useContext } from "react";
import { Link } from "react-router-dom";
import { Constants } from "../../utils";
import { useTranslation } from "react-i18next";
import { MyAvatar } from "../../Components/MyAvatar";
export default function Scanners() { export default function Scanners() {
const webSocketContext = useContext(WebSocketContext); /*const webSocketContext = useWebSocketContext()
const { t } = useTranslation(); const { t } = useTranslation();
const getTableColumns = () => { const getTableColumns = () => {
@ -144,5 +131,7 @@ export default function Scanners() {
dataSource={getTableItems()} dataSource={getTableItems()}
/> />
</> </>
); ); */
return <></>;
} }

View File

@ -38,10 +38,14 @@ import {
import { MyUserAvatar } from "../../Components/MyAvatar"; import { MyUserAvatar } from "../../Components/MyAvatar";
import { useUserProfileContext } from "../../Contexts/UserProfileContext"; import { useUserProfileContext } from "../../Contexts/UserProfileContext";
import { useWebSocketContext } from "../../Contexts/WebSocketContext"; import { useWebSocketContext } from "../../Contexts/WebSocketContext";
import { useAppContext } from "../../Contexts/AppContext";
import { useSideBarContext } from "../../Contexts/SideBarContext";
export default function UserProfile() { export default function UserProfile() {
const webSocketContext = useWebSocketContext(); const webSocketContext = useWebSocketContext();
const { userProfile, setUserProfile } = useUserProfileContext(); const appContext = useAppContext();
const sideBarContext = useSideBarContext();
const userProfileContext = useUserProfileContext();
const [notificationApi, notificationContextHolder] = const [notificationApi, notificationContextHolder] =
notification.useNotification(); notification.useNotification();
const { t, i18n } = useTranslation(); const { t, i18n } = useTranslation();
@ -182,7 +186,7 @@ export default function UserProfile() {
const getApiKeyTableItems = () => { const getApiKeyTableItems = () => {
let items = []; let items = [];
userProfile.apiKeys.forEach((apiKey) => { userProfileContext.apiKeys.forEach((apiKey) => {
items.push({ items.push({
key: apiKey.Id, key: apiKey.Id,
name: apiKey.Name, name: apiKey.Name,
@ -199,11 +203,11 @@ export default function UserProfile() {
const getSessionTableItems = () => { const getSessionTableItems = () => {
let items = []; let items = [];
userProfile.sessions.sort( userProfileContext.sessions.sort(
(a, b) => b.ConnectionStatus - a.ConnectionStatus (a, b) => b.ConnectionStatus - a.ConnectionStatus
); );
userProfile.sessions.forEach((session) => { userProfileContext.sessions.forEach((session) => {
items.push({ items.push({
key: session.IdForDeletion, key: session.IdForDeletion,
userAgent: session.UserAgent, userAgent: session.UserAgent,
@ -233,14 +237,14 @@ export default function UserProfile() {
const isButtonDisabled = () => { const isButtonDisabled = () => {
if ( if (
!isEmailValid(email) || !isEmailValid(email) ||
userProfile.username.length < Constants.GLOBALS.MIN_USERNAME_LENGTH sideBarContext.username.length < Constants.GLOBALS.MIN_USERNAME_LENGTH
) { ) {
return true; return true;
} }
if ( if (
username !== userProfile.username || username !== sideBarContext.username ||
email !== userProfile.email || email !== userProfileContext.email ||
(oldPassword !== "" && (oldPassword !== "" &&
newPassword !== "" && newPassword !== "" &&
newPassword === repeatedNewPassword) newPassword === repeatedNewPassword)
@ -254,11 +258,11 @@ export default function UserProfile() {
const handleOnSubmit = () => { const handleOnSubmit = () => {
const changes = {}; const changes = {};
if (userProfile.username !== username) { if (sideBarContext.username !== username) {
changes.username = username; changes.username = username;
} }
if (userProfile.email !== email) { if (userProfileContext.email !== email) {
changes.email = email; changes.email = email;
} }
@ -287,20 +291,24 @@ export default function UserProfile() {
useEffect(() => { useEffect(() => {
myFetch("/user/profile", "GET").then((data) => { myFetch("/user/profile", "GET").then((data) => {
setUserProfile({ userProfileContext.setEmail(data.Email);
id: data.Id, userProfileContext.setSessions(data.Sessions);
avatar: data.Avatar, userProfileContext.setApiKeys(data.ApiKeys);
username: data.Username,
email: data.Email,
sessions: data.Sessions,
apiKeys: data.ApiKeys,
});
setUsername(data.Username);
setEmail(data.Email); setEmail(data.Email);
}); });
}, []); }, []);
useEffect(
() => setUsername(sideBarContext.username),
[sideBarContext.username]
);
useEffect(
() => setEmail(userProfileContext.email),
[userProfileContext.email]
);
return ( return (
<> <>
{notificationContextHolder} {notificationContextHolder}
@ -323,7 +331,7 @@ export default function UserProfile() {
"X-Authorization": getUserSessionFromLocalStorage(), "X-Authorization": getUserSessionFromLocalStorage(),
}} }}
> >
<MyUserAvatar avatar={userProfile.avatar} size={256} /> <MyUserAvatar avatar={sideBarContext.avatar} size={256} />
</Upload> </Upload>
</Col> </Col>
@ -356,10 +364,8 @@ export default function UserProfile() {
} }
> >
<Input <Input
value={userProfile.username} value={username}
onChange={(e) => onChange={(e) => setUsername(e.target.value)}
setUserProfile({ ...userProfile, Username: e.target.value })
}
minLength={Constants.GLOBALS.MIN_USERNAME_LENGTH} minLength={Constants.GLOBALS.MIN_USERNAME_LENGTH}
maxLength={Constants.GLOBALS.MAX_USERNAME_LENGTH} maxLength={Constants.GLOBALS.MAX_USERNAME_LENGTH}
/> />
@ -367,14 +373,12 @@ export default function UserProfile() {
<Form.Item <Form.Item
label={t("userProfile.form.email")} label={t("userProfile.form.email")}
hasFeedback hasFeedback
validateStatus={!isEmailValid(userProfile.email) && "error"} validateStatus={!isEmailValid(userProfileContext.email) && "error"}
> >
<Input <Input
type="email" type="email"
value={userProfile.email} value={email}
onChange={(e) => onChange={(e) => setEmail(e.target.value)}
setUserProfile({ ...userProfile, Email: e.target.value })
}
/> />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
@ -437,7 +441,8 @@ export default function UserProfile() {
<br /> <br />
<Typography.Title level={4}> <Typography.Title level={4}>
{t("userProfile.header.yourSessions")} ({userProfile.sessions.length}) {t("userProfile.header.yourSessions")} (
{userProfileContext.sessions.length})
</Typography.Title> </Typography.Title>
<Table <Table
@ -447,7 +452,7 @@ export default function UserProfile() {
/> />
{hasPermission( {hasPermission(
userProfile.Permissions, appContext.userPermissions,
Constants.PERMISSIONS.USER_PROFILE.API_KEYS Constants.PERMISSIONS.USER_PROFILE.API_KEYS
) && ( ) && (
<> <>
@ -460,7 +465,7 @@ export default function UserProfile() {
> >
<Typography.Title level={4}> <Typography.Title level={4}>
{t("userProfile.header.yourApiKeys")} ( {t("userProfile.header.yourApiKeys")} (
{userProfile.apiKeys.length}){" "} {userProfileContext.apiKeys.length}){" "}
<Tooltip title={t("userProfile.icon.viewApiDoc")}> <Tooltip title={t("userProfile.icon.viewApiDoc")}>
<Link <Link
target="_blank" target="_blank"

View File

@ -1,6 +1,5 @@
import { Badge } from "antd"; import { Badge } from "antd";
import { createContext, useEffect, useRef, useState } from "react"; import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { Buffer } from "buffer"; import { Buffer } from "buffer";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
@ -222,7 +221,7 @@ let webSocketContextPreview = {
AdminAreaRolesPermissions: [], AdminAreaRolesPermissions: [],
}; };
export const WebSocketContext = createContext(webSocketContextPreview); //export const WebSocketContext = createContext(webSocketContextPreview);
// commands received from the backend server // commands received from the backend server
export const ReceivedMessagesCommands = { export const ReceivedMessagesCommands = {
@ -291,7 +290,7 @@ export const SentMessagesCommands = {
GroupTasksInstallPythonPackages: 21, GroupTasksInstallPythonPackages: 21,
GroupTasksInstallGlobalPythonPackages: 22, GroupTasksInstallGlobalPythonPackages: 22,
}; };
/*
export function WebSocketProvider({ export function WebSocketProvider({
children, children,
userSession, userSession,
@ -1172,8 +1171,8 @@ export function WebSocketProvider({
{children} {children}
</WebSocketContext.Provider> </WebSocketContext.Provider>
); );
} } */
/*
function scrollToNextStep(groupTaskId, step) { function scrollToNextStep(groupTaskId, step) {
setTimeout( setTimeout(
() => () =>
@ -1182,22 +1181,7 @@ function scrollToNextStep(groupTaskId, step) {
?.scrollIntoView({ behavior: "smooth" }), ?.scrollIntoView({ behavior: "smooth" }),
200 200
); );
} } */
// https://stackoverflow.com/a/52486921
function setNativeValue(element, value) {
let lastValue = element.value;
element.value = value;
let event = new Event("input", { target: element, bubbles: true });
// React 15
event.simulated = true;
// React 16
let tracker = element._valueTracker;
if (tracker) {
tracker.setValue(lastValue);
}
element.dispatchEvent(event);
}
export function FormatDatetime(datetime) { export function FormatDatetime(datetime) {
if (datetime === undefined || datetime === "0001-01-01T00:00:00Z") { if (datetime === undefined || datetime === "0001-01-01T00:00:00Z") {
@ -1273,31 +1257,33 @@ export function CapitalizeFirstLetter(string) {
} }
export function hasPermission(userPermissions, permission) { export function hasPermission(userPermissions, permission) {
return true; if (userPermissions === null) return false;
//return userPermissions.includes(permission);
return userPermissions.includes(permission);
} }
export function hasXYPermission(userPermissions, permission, xyValue) { export function hasXYPermission(userPermissions, permission, xyValue) {
return true; if (userPermissions === null) return false;
/*return userPermissions.includes(
return userPermissions.includes(
permission.replace("XY", xyValue.toLowerCase()) permission.replace("XY", xyValue.toLowerCase())
); */ );
} }
export function hasOnePermission(userPermissions, ...permissions) { export function hasOnePermission(userPermissions, ...permissions) {
return true; if (userPermissions === null) return false;
/*for (const permission of permissions) {
for (const permission of permissions) {
if (userPermissions.includes(permission)) { if (userPermissions.includes(permission)) {
return true; return true;
} }
} }
return false; */ return false;
} }
export function hasOneXYPermission(userPermissions, xyValue, ...permissions) { export function hasOneXYPermission(userPermissions, xyValue, ...permissions) {
return true; for (const permission of permissions) {
/* for (const permission of permissions) {
if ( if (
userPermissions.includes(permission.replace("XY", xyValue.toLowerCase())) userPermissions.includes(permission.replace("XY", xyValue.toLowerCase()))
) { ) {
@ -1305,7 +1291,7 @@ export function hasOneXYPermission(userPermissions, xyValue, ...permissions) {
} }
} }
return false; */ return false;
} }
export function EncodeStringToBase64(value) { export function EncodeStringToBase64(value) {