diff --git a/src/App.js b/src/App.js index 0376d49..32a52be 100644 --- a/src/App.js +++ b/src/App.js @@ -8,8 +8,14 @@ import DashboardLayout from "./Components/DashboardLayout"; import WebSocketProvider from "./Contexts/WebSocketContext"; import SideBarProvider from "./Contexts/SideBarContext"; 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() { + const [notificationApi, notificationContextHolder] = + notification.useNotification(); const { userSession, setUserSession } = UseUserSession(); const [isWebSocketReady, setIsWebSocketReady] = useState(true); @@ -26,21 +32,32 @@ export default function App() { return ( + {notificationContextHolder} + - - + + + + + + - - + + + + + + diff --git a/src/Components/AppRoutes/index.js b/src/Components/AppRoutes/index.js index 6a07580..06c3243 100644 --- a/src/Components/AppRoutes/index.js +++ b/src/Components/AppRoutes/index.js @@ -1,200 +1,180 @@ import { Route, Routes } from "react-router-dom"; -import Dashboard from "../../Pages/Dashboard"; -import { - Constants, - WebSocketContext, - hasOnePermission, - hasPermission, -} from "../../utils"; -import UserProfile from "../../Pages/UserProfile"; -import Scanners from "../../Pages/Scanners"; -import AdminAreaRoles from "../../Pages/AdminArea/Roles"; -import AdminAreaLogs from "../../Pages/AdminArea/Logs"; -import AllUsers from "../../Pages/AllUsers"; -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"; +import { Constants, hasOnePermission, hasPermission } from "../../utils"; +import { useAppContext } from "../../Contexts/AppContext"; +import { Suspense, lazy } from "react"; +import { Spin } from "antd"; + +// Lazy-loaded components +const Dashboard = lazy(() => import("../../Pages/Dashboard")); +const GroupTasks = lazy(() => import("../../Pages/GroupTasks/Overview")); +const UserProfile = lazy(() => import("../../Pages/UserProfile")); +const Scanners = lazy(() => import("../../Pages/Scanners")); +const AdminAreaRoles = lazy(() => import("../../Pages/AdminArea/Roles")); +const AdminAreaLogs = lazy(() => import("../../Pages/AdminArea/Logs")); +const AllUsers = lazy(() => import("../../Pages/AllUsers")); +const GroupTasksHistory = lazy(() => import("../../Pages/GroupTasks/History")); +const PageNotFound = lazy(() => import("../../Pages/PageNotFound")); +const EquipmentDocumentationOverview = lazy(() => + import("../../Pages/EquipmentDocumentation") +); + +function SuspenseFallback({ children }) { + return ( + + + + } + > + {children} + + ); +} export default function AppRoutes() { - // const webSocketContext = useContext(WebSocketContext); + const appContext = useAppContext(); - console.log("appRoutes"); - - /* - TODO: move down -{hasPermission( - webSocketContext.User.Permissions, - Constants.PERMISSIONS.EQUIPMENT_DOCUMENTATION.VIEW - ) && ( - } - /> - )} - - - } - /> - - - - } - /> - */ + console.info("appRoutes"); return ( - } /> - } + path="/" + element={ + + + + } /> + {hasPermission( + appContext.userPermissions, + Constants.PERMISSIONS.EQUIPMENT_DOCUMENTATION.VIEW + ) && ( + + + + } + /> + )} + } + element={ + + + + } /> } + element={ + + + + } /> - } - /> + {hasPermission( + appContext.userPermissions, + Constants.PERMISSIONS.GROUP_TASKS.HISTORY + ) && ( + + + + } + /> + )} - } /> + {hasPermission( + appContext.userPermissions, + Constants.PERMISSIONS.SCANNER.USE_SCANNERS + ) && ( + + + + } + /> + )} + - + } /> + - + } /> - } /> - - } /> - - } /> - - ); -} /* - -/* -export default function AppRoutes() { - const webSocketContext = useContext(WebSocketContext); - - /* - TODO: move down -{hasPermission( - webSocketContext.User.Permissions, - Constants.PERMISSIONS.EQUIPMENT_DOCUMENTATION.VIEW - ) && ( - } - /> - )} - - - } - /> - - - - } - /> - */ /* - - return ( - - } /> - - } - /> - - } - /> - - } - /> - - {hasPermission( - webSocketContext.User.Permissions, - Constants.PERMISSIONS.GROUP_TASKS.HISTORY - ) && ( - } - /> - )} - - {hasPermission( - webSocketContext.User.Permissions, - Constants.PERMISSIONS.SCANNER.USE_SCANNERS - ) && } />} - - } /> - - } /> - {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, Constants.PERMISSIONS.ADMIN_AREA.ROLES.MOVE_ROLE_UP_DOWN - ) && } />} + ) && ( + + + + } + /> + )} {hasPermission( - webSocketContext.User.Permissions, + appContext.userPermissions, Constants.PERMISSIONS.ADMIN_AREA.LOGS - ) && } />} + ) && ( + + + + } + /> + )} - } /> + + + + } + /> ); } -*/ diff --git a/src/Components/LogCard/index.js b/src/Components/LogCard/index.js index 5c942a2..6b6fcbe 100644 --- a/src/Components/LogCard/index.js +++ b/src/Components/LogCard/index.js @@ -4,21 +4,16 @@ import { ReloadOutlined, } from "@ant-design/icons"; import { Card, Checkbox, Popover, Space, Spin, Tooltip } from "antd"; -import { useContext, useEffect, useState } from "react"; -import { - Constants, - FormatDatetime, - WebSocketContext, - myFetch, -} from "../../utils"; +import { useEffect, useRef, useState } from "react"; +import { Constants, FormatDatetime, myFetch } from "../../utils"; import { Link } from "react-router-dom"; import { useTranslation } from "react-i18next"; export default function LogCard({ type }) { - const webSocketContext = useContext(WebSocketContext); const { t, i18n } = useTranslation(); const [checkboxInfoChecked, setCheckboxInfoChecked] = useState(true); const [checkboxErrorChecked, setCheckboxErrorChecked] = useState(true); + const fetchResponse = useRef(); const getDate = () => { const today = new Date(); @@ -56,16 +51,16 @@ export default function LogCard({ type }) { }; const getGroupTaskStepName = (groupTaskStep) => { - const foundName = webSocketContext.CategoryGroups.find( + const foundName = fetchResponse.current.CategoryGroups.find( (categoryGroup) => categoryGroup.category === - webSocketContext.GroupTasks.find( + fetchResponse.current.GroupTasks.find( (groupTask) => groupTask.Id === groupTaskStep.GroupTasksId )?.Category )?.groups.find( (groups) => groups.id === - webSocketContext.GroupTasks.find( + fetchResponse.current.GroupTasks.find( (groupTask) => groupTask.Id === groupTaskStep.GroupTasksId ).GroupId ).tasks[groupTaskStep.Step - 1]; @@ -83,6 +78,8 @@ export default function LogCard({ type }) { "GET" ) .then((data) => { + fetchResponse.current = data; + setLoadingSpinner(false); if (data.Logs === null) { @@ -119,7 +116,7 @@ export default function LogCard({ type }) { ); if (foundData !== undefined) { - const foundUser = webSocketContext.AllUsers.find( + const foundUser = fetchResponse.current.Users.find( (user) => user.Id === foundData.Value ); @@ -145,9 +142,10 @@ export default function LogCard({ type }) { ); if (foundData !== undefined) { - const foundGroupTask = webSocketContext.GroupTasks.find( - (groupTask) => groupTask.Id === foundData.Value - ); + const foundGroupTask = + fetchResponse.current.GroupTasks.find( + (groupTask) => groupTask.Id === foundData.Value + ); items.push( step.Id === foundData.Value ); @@ -243,7 +241,7 @@ export default function LogCard({ type }) { ); if (foundData !== undefined) { - const foundRole = webSocketContext.AllRoles.find( + const foundRole = fetchResponse.current.Roles.find( (role) => role.Id === foundData.Value ); @@ -295,12 +293,13 @@ export default function LogCard({ type }) { foundDataCategory !== undefined && foundDataGroupId !== undefined ) { - const foundGroup = webSocketContext.CategoryGroups.find( - (categoryGroup) => - categoryGroup.category === foundDataCategory.Value - ).groups.find( - (group) => group.id === foundDataGroupId.Value - ); + const foundGroup = + fetchResponse.current.CategoryGroups.find( + (categoryGroup) => + categoryGroup.category === foundDataCategory.Value + ).groups.find( + (group) => group.id === foundDataGroupId.Value + ); items.push( ); } - -// diff --git a/src/Components/SideMenu/index.js b/src/Components/SideMenu/index.js index 3310e69..33a2177 100644 --- a/src/Components/SideMenu/index.js +++ b/src/Components/SideMenu/index.js @@ -11,7 +11,7 @@ import { } from "@ant-design/icons"; import { Badge, Divider, Menu } from "antd"; 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 PropTypes from "prop-types"; import { Constants, hasOnePermission, hasPermission } from "../../utils"; @@ -27,7 +27,7 @@ export default function SideMenu({ setIsSideMenuCollapsed, }) { const appContext = useAppContext(); - const sidebarContext = useSideBarContext(); + const sideBarContext = useSideBarContext(); const location = useLocation(); const [selectedKeys, setSelectedKeys] = useState("/"); const { t } = useTranslation(); @@ -156,8 +156,6 @@ export default function SideMenu({ }; const getSecondMenuItems = () => { - console.log("getSecondMenuItems", sidebarContext.connectionBadgeStatus); - let items = []; if ( @@ -177,9 +175,9 @@ export default function SideMenu({ { icon: ( , + label: ` ${sideBarContext.username}`, + icon: , key: "/user-profile", }, { @@ -214,11 +212,6 @@ export default function SideMenu({ return items; }; - console.log( - "sidebarContext.connectionBadgeStatus", - sidebarContext.connectionBadgeStatus - ); - return ( useContext(AdminAreaRolesContext); + +export function AdminAreaRolesProvider({ children }) { + const [roles, setRoles] = useState([]); + const [rolesPermissions, setRolesPermissions] = useState([]); + + return ( + + {children} + + ); +} diff --git a/src/Contexts/AppContext.js b/src/Contexts/AppContext.js index bbac62b..832fd0f 100644 --- a/src/Contexts/AppContext.js +++ b/src/Contexts/AppContext.js @@ -1,11 +1,9 @@ -import { createContext, useContext, useState } from "react"; -import { Constants } from "../utils"; +import { createContext, useContext, useRef, useState } from "react"; const preview = { - username: "", - avatar: "", + userId: "", userPermissions: [], - availableGroupTasks: [], + users: [], }; const AppContext = createContext(preview); @@ -13,22 +11,19 @@ const AppContext = createContext(preview); export const useAppContext = () => useContext(AppContext); export function AppProvider({ children }) { - const [username, setUsername] = useState(Constants.LOADING); - const [avatar, setAvatar] = useState(""); + const userId = useRef(""); // used for some conditions in webSocket message handler + const [userPermissions, setUserPermissions] = useState([]); - const [availableGroupTasks, setAvailableGroupTasks] = useState([]); + const [users, setUsers] = useState([]); // TODO: realy need this? return ( {children} diff --git a/src/Contexts/GroupTasksContext.js b/src/Contexts/GroupTasksContext.js new file mode 100644 index 0000000..1aefe8a --- /dev/null +++ b/src/Contexts/GroupTasksContext.js @@ -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 ( + + {children} + + ); +} diff --git a/src/Contexts/SideBarContext.js b/src/Contexts/SideBarContext.js index 7595972..51e45a8 100644 --- a/src/Contexts/SideBarContext.js +++ b/src/Contexts/SideBarContext.js @@ -1,9 +1,13 @@ import { createContext, useContext, useState } from "react"; +import { Constants } from "../utils"; const preview = { connectionBadgeStatus: "", connectedUsers: 0, selectedScanner: "", + username: "", + avatar: "", + availableGroupTasks: [], }; const SideBarContext = createContext(preview); @@ -14,6 +18,9 @@ export default function SideBarProvider({ children }) { const [connectionBadgeStatus, setConnectionBadgeStatus] = useState("error"); const [connectedUsers, setConnectedUsers] = useState(0); const [selectedScanner, setSelectedScanner] = useState(""); + const [username, setUsername] = useState(Constants.LOADING); // + const [avatar, setAvatar] = useState(""); + const [availableGroupTasks, setAvailableGroupTasks] = useState([]); return ( {children} diff --git a/src/Contexts/UserProfileContext.js b/src/Contexts/UserProfileContext.js index ca85951..8411931 100644 --- a/src/Contexts/UserProfileContext.js +++ b/src/Contexts/UserProfileContext.js @@ -1,25 +1,33 @@ import { createContext, useContext, useState } from "react"; import { Constants } from "../utils"; -// only for tab completion +// userId, username is stored in appContext const preview = { - id: Constants.LOADING, - avatar: "", - username: Constants.LOADING, email: Constants.LOADING, sessions: [], apiKeys: [], }; -const UserProfileContext = createContext({ userProfile: preview }); +const UserProfileContext = createContext(preview); export const useUserProfileContext = () => useContext(UserProfileContext); export function UserProfileProvider({ children }) { - const [userProfile, setUserProfile] = useState(preview); + const [email, setEmail] = useState(""); + const [sessions, setSessions] = useState([]); + const [apiKeys, setApiKeys] = useState([]); return ( - + {children} ); diff --git a/src/Contexts/WebSocketContext.js b/src/Contexts/WebSocketContext.js index 9a3ae3b..8663be6 100644 --- a/src/Contexts/WebSocketContext.js +++ b/src/Contexts/WebSocketContext.js @@ -1,8 +1,14 @@ -import { createContext, useContext, useEffect, useRef, useState } from "react"; -import { Constants, ReceivedMessagesCommands, myFetch } from "../utils"; +import { createContext, useContext, useEffect, useRef } from "react"; +import { Constants, myFetch } from "../utils"; import { useSideBarContext } from "./SideBarContext"; import { useAppContext } from "./AppContext"; 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); @@ -14,10 +20,16 @@ export default function WebSocketProvider({ setUserSession, isWebSocketReady, setIsWebSocketReady, + notificationApi, }) { const ws = useRef(null); + const navigate = useNavigate(); const appContext = useAppContext(); const sideBarContext = useSideBarContext(); + const groupTasksContext = useGroupTasksContext(); + const userProfileContext = useUserProfileContext(); + const adminAreaRolesContext = useAdminAreaRolesContext(); + const usersContext = useUsersContext(); const connect = () => { ws.current = new WebSocket(`${Constants.WS_ADDRESS}?auth=${userSession}`); @@ -28,27 +40,29 @@ export default function WebSocketProvider({ 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); + appContext.userId.current = data.UserId; + appContext.setUserPermissions( + data.Permissions === null ? [] : data.Permissions + ); + appContext.setUsers(data.Users); + sideBarContext.setUsername(data.Username); + sideBarContext.setAvatar(data.Avatar); + sideBarContext.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; - } + handleWebSocketMessage( + event, + navigate, + notificationApi, + sideBarContext, + appContext, + groupTasksContext, + userProfileContext, + adminAreaRolesContext, + usersContext + ); }; ws.current.onclose = (event) => { diff --git a/src/Handlers/WebSocketMessageHandler.js b/src/Handlers/WebSocketMessageHandler.js index b52cd90..864ccd3 100644 --- a/src/Handlers/WebSocketMessageHandler.js +++ b/src/Handlers/WebSocketMessageHandler.js @@ -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); +} diff --git a/src/Pages/AdminArea/Roles/index.js b/src/Pages/AdminArea/Roles/index.js index 5e0a887..b61e83d 100644 --- a/src/Pages/AdminArea/Roles/index.js +++ b/src/Pages/AdminArea/Roles/index.js @@ -15,8 +15,8 @@ import { import { Constants, SentMessagesCommands, - WebSocketContext, hasPermission, + myFetch, } from "../../../utils"; import { ArrowDownOutlined, @@ -28,15 +28,20 @@ import { QuestionCircleOutlined, SaveOutlined, } from "@ant-design/icons"; -import { useContext, useState } from "react"; +import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { MyAvatar } from "../../../Components/MyAvatar"; +import { useAdminAreaRolesContext } from "../../../Contexts/AdminAreaRolesContext"; +import { useWebSocketContext } from "../../../Contexts/WebSocketContext"; +import { useAppContext } from "../../../Contexts/AppContext"; const { useBreakpoint } = Grid; export default function AdminAreaRoles() { const { t } = useTranslation(); - const webSocketContext = useContext(WebSocketContext); + const webSocketContext = useWebSocketContext(); + const appContext = useAppContext(); + const adminAreaRolesContext = useAdminAreaRolesContext(); const [notificationApi, notificationContextHolder] = notification.useNotification(); @@ -97,7 +102,9 @@ export default function AdminAreaRoles() { }; const getRolePermissions = (role) => { - const rolePermissions = webSocketContext.AdminAreaRolesPermissions.find( + if (role === undefined) return []; + + const rolePermissions = adminAreaRolesContext.rolesPermissions.find( (r) => r.RoleId === role.Id ); @@ -110,25 +117,34 @@ export default function AdminAreaRoles() { const treeData = createTreeDataList( 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 ( {notificationContextHolder} - {webSocketContext.AllRoles.map((role) => ( + {adminAreaRolesContext.roles.map((role) => ( ))} {hasPermission( - webSocketContext.User.Permissions, + appContext.userPermissions, Constants.PERMISSIONS.ADMIN_AREA.ROLES.CREATE_NEW_ROLE ) && (
{ - const rolePermissions = webSocketContext.AdminAreaRolesPermissions.find( + const rolePermissions = adminAreaRolesContext.rolesPermissions.find( (r) => r.RoleId === role.Id ); @@ -182,10 +205,10 @@ function Role({ treeData, role, webSocketContext, notificationApi }) { setCheckedTreeKeyPermissions(checkedKeys); const getMasterPermissions = () => { - return webSocketContext.AdminAreaRolesPermissions.find( + return adminAreaRolesContext.rolesPermissions.find( (role) => role.RoleId === - webSocketContext.AllRoles.find((role) => role.Master === true).Id + adminAreaRolesContext.roles.find((role) => role.Master === true).Id ).Permissions; }; @@ -335,7 +358,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) { }; const getUsersInRole = () => { - return webSocketContext.AllUsers.filter((user) => user.RoleId === role.Id); + return appContext.users.filter((user) => user.RoleId === role.Id); }; const UserAvatarsInRole = () => { @@ -378,7 +401,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) { }; const getMaxRoleSortingOrder = () => { - return webSocketContext.AllRoles[webSocketContext.AllRoles.length - 1] + return adminAreaRolesContext.roles[adminAreaRolesContext.roles.length - 1] .SortingOrder; }; @@ -392,7 +415,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) { extra: editMode ? ( {hasPermission( - webSocketContext.User.Permissions, + appContext.userPermissions, Constants.PERMISSIONS.ADMIN_AREA.ROLES.DELETE_ROLE ) && ( <> @@ -422,7 +445,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) { )} {hasPermission( - webSocketContext.User.Permissions, + appContext.userPermissions, Constants.PERMISSIONS.ADMIN_AREA.ROLES.MOVE_ROLE_UP_DOWN ) && ( <> @@ -454,7 +477,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) { )} {hasPermission( - webSocketContext.User.Permissions, + appContext.userPermissions, Constants.PERMISSIONS.ADMIN_AREA.ROLES.UPDATE_ROLE ) && ( diff --git a/src/Pages/AllUsers/CreateUserModal.js b/src/Pages/AllUsers/CreateUserModal.js index ff596e0..475dbd2 100644 --- a/src/Pages/AllUsers/CreateUserModal.js +++ b/src/Pages/AllUsers/CreateUserModal.js @@ -4,14 +4,16 @@ import { Constants, EncodeStringToBase64, SentMessagesCommands, - WebSocketContext, isEmailValid, } from "../../utils"; -import { useContext, useState } from "react"; +import { useState } from "react"; import { useTranslation } from "react-i18next"; +import { useWebSocketContext } from "../../Contexts/WebSocketContext"; +import { useUsersContext } from "../../Contexts/UsersContext"; export default function CreateUserModal({ isModalOpen, setIsModalOpen }) { - const webSocketContext = useContext(WebSocketContext); + const webSocketContext = useWebSocketContext(); + const usersContext = useUsersContext(); const { t } = useTranslation(); const [username, setUsername] = useState(""); const [email, setEmail] = useState(""); @@ -121,7 +123,7 @@ export default function CreateUserModal({ isModalOpen, setIsModalOpen }) { onChange={(e) => setSelectedRoleId(e)} placeholder={t("allUsers.createUserModal.form.role.placeholder")} > - {webSocketContext.AllRoles.map((role) => ( + {usersContext.roles.map((role) => ( {role.DisplayName} ))} diff --git a/src/Pages/AllUsers/index.js b/src/Pages/AllUsers/index.js index 7ec9222..54eec58 100644 --- a/src/Pages/AllUsers/index.js +++ b/src/Pages/AllUsers/index.js @@ -332,8 +332,6 @@ 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); diff --git a/src/Pages/Dashboard/index.js b/src/Pages/Dashboard/index.js index c8484f0..2e8e9cb 100644 --- a/src/Pages/Dashboard/index.js +++ b/src/Pages/Dashboard/index.js @@ -1,6 +1,6 @@ -import React, { useContext } from "react"; -import { WebSocketContext } from "../../utils"; +import { memo } from "react"; import { Card, Typography } from "antd"; +import { useSideBarContext } from "../../Contexts/SideBarContext"; const randomGreeting = Math.floor(Math.random() * 18); @@ -105,13 +105,13 @@ function getGreeting(name) { return greeting; } -const Dashboard = React.memo(() => { - const webSocketContext = useContext(WebSocketContext); +const Dashboard = memo(() => { + const sideBarContext = useSideBarContext(); return ( - {getGreeting(webSocketContext.User.Username)} + {getGreeting(sideBarContext.username)} ); diff --git a/src/Pages/EquipmentDocumentation/ViewEquipmentDocumentation.js b/src/Pages/EquipmentDocumentation/ViewEquipmentDocumentation.js index 481001b..5af691e 100644 --- a/src/Pages/EquipmentDocumentation/ViewEquipmentDocumentation.js +++ b/src/Pages/EquipmentDocumentation/ViewEquipmentDocumentation.js @@ -1,13 +1,7 @@ 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 { - AppStyle, - Constants, - FormatDatetime, - WebSocketContext, - myFetch, -} from "../../utils"; +import { AppStyle, Constants, FormatDatetime, myFetch } from "../../utils"; import { BookOutlined, InfoCircleOutlined, @@ -17,10 +11,11 @@ import EditEquipmentDocumentationModal from "./EditEquipmentDocumentationModal"; import { NoteComponent } from "."; import { useTranslation } from "react-i18next"; import { MyAvatar } from "../../Components/MyAvatar"; +import { useAppContext } from "../../Contexts/AppContext"; export default function ViewEquipmentDocumentations({ scannerResult }) { const { t } = useTranslation(); - const webSocketContext = useContext(WebSocketContext); + const appContext = useAppContext(); console.log("render ViewEquipmentDocumentations"); @@ -137,7 +132,7 @@ export default function ViewEquipmentDocumentations({ scannerResult }) { }} > diff --git a/src/Pages/GroupTasks/Overview/GroupTasksTableList.js b/src/Pages/GroupTasks/Overview/GroupTasksTableList.js index d937675..e87ed6c 100644 --- a/src/Pages/GroupTasks/Overview/GroupTasksTableList.js +++ b/src/Pages/GroupTasks/Overview/GroupTasksTableList.js @@ -20,13 +20,13 @@ import { FormatDatetime, GetDuration, SentMessagesCommands, - WebSocketContext, hasOneXYPermission, hasXYPermission, } from "../../../utils"; -import { useContext } from "react"; import { useTranslation } from "react-i18next"; import { MyAvatar } from "../../../Components/MyAvatar"; +import { useWebSocketContext } from "../../../Contexts/WebSocketContext"; +import { useAppContext } from "../../../Contexts/AppContext"; const { useBreakpoint } = Grid; @@ -35,7 +35,8 @@ export default function GroupTaskTableList({ showGroupTypeSelectionModal, groupTasks, }) { - const webSocketContext = useContext(WebSocketContext); + const webSocketContext = useWebSocketContext(); + const appContext = useAppContext(); const { t } = useTranslation(); const screenBreakpoint = useBreakpoint(); @@ -167,7 +168,7 @@ export default function GroupTaskTableList({ groupTasks.forEach((groupTask) => { if (groupTask.Category === categoryGroup.category) { - const user = webSocketContext.AllUsers.find( + const user = appContext.users.find( (user) => user.Id === groupTask.CreatorUserId ); @@ -233,7 +234,7 @@ export default function GroupTaskTableList({ {categoryGroup.category} {hasOneXYPermission( - webSocketContext.User.Permissions, + appContext.userPermissions, categoryGroup.category, Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYNewTask, Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYReloadGroupConfig, @@ -245,7 +246,7 @@ export default function GroupTaskTableList({ }} > {hasXYPermission( - webSocketContext.User.Permissions, + appContext.userPermissions, Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYNewTask, categoryGroup.category ) && ( @@ -281,7 +282,7 @@ export default function GroupTaskTableList({ } > {hasXYPermission( - webSocketContext.User.Permissions, + appContext.userPermissions, Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW .XYInstallPythonPackages, categoryGroup.category @@ -310,7 +311,7 @@ export default function GroupTaskTableList({ )} {hasXYPermission( - webSocketContext.User.Permissions, + appContext.userPermissions, Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYReloadGroupConfig, categoryGroup.category ) && ( diff --git a/src/Pages/GroupTasks/Overview/GroupTasksViewModal.js b/src/Pages/GroupTasks/Overview/GroupTasksViewModal.js index efcb5a3..668d852 100644 --- a/src/Pages/GroupTasks/Overview/GroupTasksViewModal.js +++ b/src/Pages/GroupTasks/Overview/GroupTasksViewModal.js @@ -10,12 +10,11 @@ import { Tag, notification, } from "antd"; -import { useContext, useRef, useState } from "react"; +import { useRef, useState } from "react"; import { useNavigate, useParams } from "react-router-dom"; import { Constants, FormatDatetime, - WebSocketContext, SentMessagesCommands, GetDuration, getUserId, @@ -35,9 +34,14 @@ import { useTranslation } from "react-i18next"; import { MyAvatar } from "../../../Components/MyAvatar"; import MyModal, { MyNotFoundModal } from "../../../Components/MyModal"; 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 }) { - const webSocketContext = useContext(WebSocketContext); + const webSocketContext = useWebSocketContext(); + const appContext = useAppContext(); + const groupTasksContext = useGroupTasksContext(); const navigate = useNavigate(); const [notificationApi, notificationContextHolder] = notification.useNotification(); @@ -47,7 +51,7 @@ export default function GroupTasksViewModal({ isOpen }) { const handleCancel = () => navigate(Constants.ROUTE_PATHS.GROUP_TASKS); let currentGroupTask; - webSocketContext.GroupTasks.forEach((groupTask) => { + groupTasksContext.groupTasks.forEach((groupTask) => { if (groupTask.Id === paramGroupTaskId) { currentGroupTask = groupTask; } @@ -57,7 +61,7 @@ export default function GroupTasksViewModal({ isOpen }) { if ( !currentGroupTask || !hasXYPermission( - webSocketContext.User.Permissions, + appContext.userPermissions, Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYView, currentGroupTask.Category ) @@ -231,9 +235,9 @@ export default function GroupTasksViewModal({ isOpen }) { }; const ActionHandler = ({ status, taskStepId, index, taskLocked }) => { - const currentStepTask = webSocketContext.CategoryGroups.find( - (category) => category.category === currentGroupTask.Category - ).groups.find((group) => group.id === currentGroupTask.GroupId).tasks[ + const currentStepTask = groupTasksContext.categoryGroups + .find((category) => category.category === currentGroupTask.Category) + .groups.find((group) => group.id === currentGroupTask.GroupId).tasks[ index ]; @@ -325,7 +329,7 @@ export default function GroupTasksViewModal({ isOpen }) { let groupTaskSteps = []; let groupTasks = []; - webSocketContext.GroupTasksSteps.forEach((step) => { + groupTasksContext.groupTasksSteps.forEach((step) => { if (step.GroupTasksId === paramGroupTaskId) { groupTaskSteps.push(step); } @@ -333,7 +337,7 @@ export default function GroupTasksViewModal({ isOpen }) { groupTaskSteps.sort((a, b) => a.Step - b.Step); - webSocketContext.CategoryGroups.forEach((categoryGroup) => { + groupTasksContext.categoryGroups.forEach((categoryGroup) => { if (categoryGroup.category === currentGroupTask.Category) { categoryGroup.groups.forEach((group) => { if (currentGroupTask.GroupId === group.id) { @@ -557,7 +561,7 @@ export default function GroupTasksViewModal({ isOpen }) { {notificationContextHolder} - {webSocketContext.GroupTasks.map((groupTask) => { + {groupTasksContext.groupTasks.map((groupTask) => { if (groupTask.Id === paramGroupTaskId) { let currentGroupTask = groupTask; @@ -637,11 +641,12 @@ export default function GroupTasksViewModal({ isOpen }) { > { - webSocketContext.CategoryGroups.find( - (categoryGroup) => - categoryGroup.category === - currentGroupTask.Category - ) + groupTasksContext.categoryGroups + .find( + (categoryGroup) => + categoryGroup.category === + currentGroupTask.Category + ) .groups.find( (group) => group.id === diff --git a/src/Pages/GroupTasks/Overview/GroupTypeSelectionModal.js b/src/Pages/GroupTasks/Overview/GroupTypeSelectionModal.js index efd5d54..d7db552 100644 --- a/src/Pages/GroupTasks/Overview/GroupTypeSelectionModal.js +++ b/src/Pages/GroupTasks/Overview/GroupTypeSelectionModal.js @@ -10,15 +10,12 @@ import { Tag, notification, } from "antd"; -import { - WebSocketContext, - SentMessagesCommands, - GetUuid, -} from "../../../utils"; -import { useContext } from "react"; +import { SentMessagesCommands, GetUuid } from "../../../utils"; import { InfoCircleOutlined } from "@ant-design/icons"; import TextArea from "antd/es/input/TextArea"; import { useTranslation } from "react-i18next"; +import { useWebSocketContext } from "../../../Contexts/WebSocketContext"; +import { useGroupTasksContext } from "../../../Contexts/GroupTasksContext"; export default function GroupTypeSelectionModal({ isOpen, @@ -29,7 +26,8 @@ export default function GroupTypeSelectionModal({ }) { const [notificationApi, notificationContextHolder] = notification.useNotification(); - const webSocketContext = useContext(WebSocketContext); + const webSocketContext = useWebSocketContext(); + const groupTasksContext = useGroupTasksContext(); const { t } = useTranslation(); const handleCancel = () => setIsOpen(false); @@ -135,7 +133,8 @@ export default function GroupTypeSelectionModal({ const rememberId = GetUuid(); - webSocketContext.StartGroupTasksOpenModalRememberIdRef.current = rememberId; + groupTasksContext.startGroupTasksOpenModalRememberIdRef.current = + rememberId; webSocketContext.SendSocketMessage(SentMessagesCommands.StartGroupTasks, { category: categoryGroup.category, diff --git a/src/Pages/GroupTasks/Overview/index.js b/src/Pages/GroupTasks/Overview/index.js index b3bff5d..80bc5c5 100644 --- a/src/Pages/GroupTasks/Overview/index.js +++ b/src/Pages/GroupTasks/Overview/index.js @@ -1,25 +1,31 @@ import { Button, Col, Popconfirm, Result, Row } from "antd"; -import { useContext, useState } from "react"; +import { useEffect, useState } from "react"; import GroupTasksViewModal from "./GroupTasksViewModal"; import GroupTypeSelectionModal from "./GroupTypeSelectionModal"; import GroupTaskTableList from "./GroupTasksTableList"; import { Constants, SentMessagesCommands, - WebSocketContext, hasPermission, hasXYPermission, + myFetch, } from "../../../utils"; import { useTranslation } from "react-i18next"; 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 }) { + const webSocketContext = useWebSocketContext(); + const appContext = useAppContext(); + const groupTasksContext = useGroupTasksContext(); + const [isGroupTypeSelectionModalOpen, setIsGroupTypeSelectionModalOpen] = useState(false); const [currentCategoryGroup, setCurrentCategoryGroup] = useState([]); const [currentSelectedModalGroupType, setCurrentSelectedModalGroupType] = useState(); - const webSocketContext = useContext(WebSocketContext); const { t } = useTranslation(); const showGroupTypeSelectionModal = (categoryGroup) => { @@ -28,10 +34,10 @@ export default function GroupTasks({ isGroupTasksViewModalOpen }) { setCurrentSelectedModalGroupType(null); }; - const filteredCategoryGroups = webSocketContext.CategoryGroups.filter( + const filteredCategoryGroups = groupTasksContext.categoryGroups.filter( (categoryGroup) => hasXYPermission( - webSocketContext.User.Permissions, + appContext.userPermissions, Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYView, 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 ( <> - {webSocketContext.CategoryGroups.length === 0 ? ( + {groupTasksContext.categoryGroups.length === 0 ? ( ) : ( <> @@ -66,7 +82,7 @@ export default function GroupTasks({ isGroupTasksViewModalOpen }) { md={{ span: 8, offset: 16 }} > {hasPermission( - webSocketContext.User.Permissions, + appContext.userPermissions, Constants.PERMISSIONS.GROUP_TASKS .INSTALL_GLOBAL_PYTHON_PACKAGES ) && ( @@ -104,7 +120,7 @@ export default function GroupTasks({ isGroupTasksViewModalOpen }) { key={categoryGroup.category} categoryGroup={categoryGroup} showGroupTypeSelectionModal={showGroupTypeSelectionModal} - groupTasks={webSocketContext.GroupTasks} + groupTasks={groupTasksContext.groupTasks} /> ); })} @@ -131,7 +147,7 @@ export default function GroupTasks({ isGroupTasksViewModalOpen }) { {hasPermission( - webSocketContext.User.Permissions, + appContext.userPermissions, Constants.PERMISSIONS.GROUP_TASKS.CHECKING_FOR_CATEGORY_GROUP_CHANGES ) && (
{ @@ -144,5 +131,7 @@ export default function Scanners() { dataSource={getTableItems()} /> - ); + ); */ + + return <>; } diff --git a/src/Pages/UserProfile/index.js b/src/Pages/UserProfile/index.js index ca29c1f..dd996f5 100644 --- a/src/Pages/UserProfile/index.js +++ b/src/Pages/UserProfile/index.js @@ -38,10 +38,14 @@ import { import { MyUserAvatar } from "../../Components/MyAvatar"; import { useUserProfileContext } from "../../Contexts/UserProfileContext"; import { useWebSocketContext } from "../../Contexts/WebSocketContext"; +import { useAppContext } from "../../Contexts/AppContext"; +import { useSideBarContext } from "../../Contexts/SideBarContext"; export default function UserProfile() { const webSocketContext = useWebSocketContext(); - const { userProfile, setUserProfile } = useUserProfileContext(); + const appContext = useAppContext(); + const sideBarContext = useSideBarContext(); + const userProfileContext = useUserProfileContext(); const [notificationApi, notificationContextHolder] = notification.useNotification(); const { t, i18n } = useTranslation(); @@ -182,7 +186,7 @@ export default function UserProfile() { const getApiKeyTableItems = () => { let items = []; - userProfile.apiKeys.forEach((apiKey) => { + userProfileContext.apiKeys.forEach((apiKey) => { items.push({ key: apiKey.Id, name: apiKey.Name, @@ -199,11 +203,11 @@ export default function UserProfile() { const getSessionTableItems = () => { let items = []; - userProfile.sessions.sort( + userProfileContext.sessions.sort( (a, b) => b.ConnectionStatus - a.ConnectionStatus ); - userProfile.sessions.forEach((session) => { + userProfileContext.sessions.forEach((session) => { items.push({ key: session.IdForDeletion, userAgent: session.UserAgent, @@ -233,14 +237,14 @@ export default function UserProfile() { const isButtonDisabled = () => { if ( !isEmailValid(email) || - userProfile.username.length < Constants.GLOBALS.MIN_USERNAME_LENGTH + sideBarContext.username.length < Constants.GLOBALS.MIN_USERNAME_LENGTH ) { return true; } if ( - username !== userProfile.username || - email !== userProfile.email || + username !== sideBarContext.username || + email !== userProfileContext.email || (oldPassword !== "" && newPassword !== "" && newPassword === repeatedNewPassword) @@ -254,11 +258,11 @@ export default function UserProfile() { const handleOnSubmit = () => { const changes = {}; - if (userProfile.username !== username) { + if (sideBarContext.username !== username) { changes.username = username; } - if (userProfile.email !== email) { + if (userProfileContext.email !== email) { changes.email = email; } @@ -287,20 +291,24 @@ export default function UserProfile() { 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, - }); + userProfileContext.setEmail(data.Email); + userProfileContext.setSessions(data.Sessions); + userProfileContext.setApiKeys(data.ApiKeys); - setUsername(data.Username); setEmail(data.Email); }); }, []); + useEffect( + () => setUsername(sideBarContext.username), + [sideBarContext.username] + ); + + useEffect( + () => setEmail(userProfileContext.email), + [userProfileContext.email] + ); + return ( <> {notificationContextHolder} @@ -323,7 +331,7 @@ export default function UserProfile() { "X-Authorization": getUserSessionFromLocalStorage(), }} > - + @@ -356,10 +364,8 @@ export default function UserProfile() { } > - setUserProfile({ ...userProfile, Username: e.target.value }) - } + value={username} + onChange={(e) => setUsername(e.target.value)} minLength={Constants.GLOBALS.MIN_USERNAME_LENGTH} maxLength={Constants.GLOBALS.MAX_USERNAME_LENGTH} /> @@ -367,14 +373,12 @@ export default function UserProfile() { - setUserProfile({ ...userProfile, Email: e.target.value }) - } + value={email} + onChange={(e) => setEmail(e.target.value)} /> - {t("userProfile.header.yourSessions")} ({userProfile.sessions.length}) + {t("userProfile.header.yourSessions")} ( + {userProfileContext.sessions.length}) {hasPermission( - userProfile.Permissions, + appContext.userPermissions, Constants.PERMISSIONS.USER_PROFILE.API_KEYS ) && ( <> @@ -460,7 +465,7 @@ export default function UserProfile() { > {t("userProfile.header.yourApiKeys")} ( - {userProfile.apiKeys.length}){" "} + {userProfileContext.apiKeys.length}){" "} ); -} - +} */ +/* function scrollToNextStep(groupTaskId, step) { setTimeout( () => @@ -1182,22 +1181,7 @@ function scrollToNextStep(groupTaskId, step) { ?.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); -} +} */ export function FormatDatetime(datetime) { if (datetime === undefined || datetime === "0001-01-01T00:00:00Z") { @@ -1273,31 +1257,33 @@ export function CapitalizeFirstLetter(string) { } export function hasPermission(userPermissions, permission) { - return true; - //return userPermissions.includes(permission); + if (userPermissions === null) return false; + + return userPermissions.includes(permission); } export function hasXYPermission(userPermissions, permission, xyValue) { - return true; - /*return userPermissions.includes( + if (userPermissions === null) return false; + + return userPermissions.includes( permission.replace("XY", xyValue.toLowerCase()) - ); */ + ); } export function hasOnePermission(userPermissions, ...permissions) { - return true; - /*for (const permission of permissions) { + if (userPermissions === null) return false; + + for (const permission of permissions) { if (userPermissions.includes(permission)) { return true; } } - return false; */ + return false; } export function hasOneXYPermission(userPermissions, xyValue, ...permissions) { - return true; - /* for (const permission of permissions) { + for (const permission of permissions) { if ( 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) {