diff --git a/src/App.js b/src/App.js index 32a52be..d753e68 100644 --- a/src/App.js +++ b/src/App.js @@ -17,7 +17,7 @@ export default function App() { const [notificationApi, notificationContextHolder] = notification.useNotification(); const { userSession, setUserSession } = UseUserSession(); - const [isWebSocketReady, setIsWebSocketReady] = useState(true); + const [isWebSocketReady, setIsWebSocketReady] = useState(false); if (!userSession) { return ; diff --git a/src/Components/AppRoutes/index.js b/src/Components/AppRoutes/index.js index 023d371..6ded517 100644 --- a/src/Components/AppRoutes/index.js +++ b/src/Components/AppRoutes/index.js @@ -48,17 +48,6 @@ function SuspenseFallback({ children }) { export default function AppRoutes() { const appContext = useAppContext(); - /* - - - - } - /> - */ - console.info("appRoutes"); return ( @@ -169,7 +158,7 @@ export default function AppRoutes() { Constants.PERMISSIONS.SCANNER.USE_SCANNERS ) && ( @@ -179,7 +168,7 @@ export default function AppRoutes() { )} @@ -188,7 +177,7 @@ export default function AppRoutes() { /> @@ -204,7 +193,7 @@ export default function AppRoutes() { Constants.PERMISSIONS.ADMIN_AREA.ROLES.MOVE_ROLE_UP_DOWN ) && ( @@ -218,7 +207,7 @@ export default function AppRoutes() { Constants.PERMISSIONS.ADMIN_AREA.LOGS ) && ( diff --git a/src/Components/SideMenu/index.js b/src/Components/SideMenu/index.js index 4e996ef..7dfcdf5 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 { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { useLocation, useNavigate } from "react-router-dom"; import PropTypes from "prop-types"; import { Constants, hasOnePermission, hasPermission } from "../../utils"; @@ -19,6 +19,8 @@ import { useTranslation } from "react-i18next"; import { MyUserAvatar } from "../MyAvatar"; import { useSideBarContext } from "../../Contexts/SideBarContext"; import { useAppContext } from "../../Contexts/AppContext"; +import { useWebSocketContext } from "../../Contexts/WebSocketContext"; +import { SentMessagesCommands } from "../../Handlers/WebSocketMessageHandler"; export default function SideMenu({ userSession, @@ -27,12 +29,12 @@ export default function SideMenu({ setIsSideMenuCollapsed, }) { const appContext = useAppContext(); + const webSocketContext = useWebSocketContext(); const sideBarContext = useSideBarContext(); const location = useLocation(); const [selectedKeys, setSelectedKeys] = useState("/"); const { t } = useTranslation(); - - useEffect(() => setSelectedKeys(location.pathname), [location.pathname]); + const lastSubscribedTopic = useRef(""); const navigate = useNavigate(); @@ -70,7 +72,7 @@ export default function SideMenu({ items.push({ label: t("sideMenu.equipmentDocumentation"), icon: , - key: "/equipment-documentation", + key: Constants.ROUTE_PATHS.EQUIPMENT_DOCUMENTATION, }); } @@ -148,7 +150,7 @@ export default function SideMenu({ adminArea.children.push({ label: t("sideMenu.adminArea.roles"), icon: , - key: "/admin-area/roles", + key: Constants.ROUTE_PATHS.ADMIN_AREA_ROLES, }); } @@ -161,7 +163,7 @@ export default function SideMenu({ adminArea.children.push({ label: t("sideMenu.adminArea.logs"), icon: , - key: "/admin-area/logs", + key: Constants.ROUTE_PATHS.ADMIN_AREA_LOGS, }); } @@ -184,7 +186,7 @@ export default function SideMenu({ items.push({ icon: , label: getCurrentUsedScannerName(), - key: "/scanners", + key: Constants.ROUTE_PATHS.SCANNERS, }); } @@ -201,12 +203,12 @@ export default function SideMenu({ }`} /> ), - key: "/users", + key: Constants.ROUTE_PATHS.USERS, }, { label: ` ${sideBarContext.username}`, icon: , - key: "/user-profile", + key: Constants.ROUTE_PATHS.USER_PROFILE, }, { label: t("sideMenu.logout"), @@ -230,6 +232,22 @@ export default function SideMenu({ return items; }; + useEffect(() => { + console.log("useeffect side menu"); + }, []); + + useEffect(() => { + console.log("useeffect side menu 2"); + + setSelectedKeys(location.pathname); + + lastSubscribedTopic.current = location.pathname; + + webSocketContext.SendSocketMessage(SentMessagesCommands.SubscribeToTopic, { + topic: location.pathname, + }); + }, [location.pathname]); + return ( diff --git a/src/Contexts/WebSocketContext.js b/src/Contexts/WebSocketContext.js index b233aa3..f5977ab 100644 --- a/src/Contexts/WebSocketContext.js +++ b/src/Contexts/WebSocketContext.js @@ -2,7 +2,6 @@ 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"; @@ -23,6 +22,7 @@ export default function WebSocketProvider({ notificationApi, }) { const ws = useRef(null); + const wsMessageCache = useRef([]); const navigate = useNavigate(); const appContext = useAppContext(); const sideBarContext = useSideBarContext(); @@ -49,6 +49,15 @@ export default function WebSocketProvider({ sideBarContext.setAvatar(data.Avatar); sideBarContext.setAvailableCategoryGroups(data.AvailableCategoryGroups); }); + + if (wsMessageCache.current.length > 0) { + // send cached messages + wsMessageCache.current.forEach((message) => { + ws.current.send(JSON.stringify(message)); + }); + + wsMessageCache.current = []; + } }; ws.current.onmessage = (event) => { @@ -88,7 +97,7 @@ export default function WebSocketProvider({ }; const SendSocketMessage = (cmd, body) => { - if (isWebSocketReady) { + if (isWebSocketReady && ws.current !== null) { ws.current.send(JSON.stringify({ Cmd: cmd, Body: body })); } else { /*notificationApi["error"]({ @@ -96,7 +105,9 @@ export default function WebSocketProvider({ description: `Please check your internet connection`, }); */ - message.error(`Websocket is not ready`); + wsMessageCache.current.push({ Cmd: cmd, Body: body }); + + // message.error(`Websocket is not ready`); } }; diff --git a/src/Handlers/WebSocketMessageHandler.js b/src/Handlers/WebSocketMessageHandler.js index 864ccd3..198207f 100644 --- a/src/Handlers/WebSocketMessageHandler.js +++ b/src/Handlers/WebSocketMessageHandler.js @@ -43,6 +43,7 @@ export const ReceivedMessagesCommands = { InstallingGlobalPythonPackages: 36, InstallingGlobalPythonPackagesFailed: 37, InstallingGlobalPythonPackagesFinished: 38, + UpdateUsers: 39, }; // commands sent to the backend server @@ -69,6 +70,7 @@ export const SentMessagesCommands = { DeleteUserApiKey: 20, GroupTasksInstallPythonPackages: 21, GroupTasksInstallGlobalPythonPackages: 22, + SubscribeToTopic: 23, }; export function handleWebSocketMessage( @@ -89,20 +91,7 @@ export function handleWebSocketMessage( 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; - }); + sideBarContext.setConnectedUsers(body); break; case ReceivedMessagesCommands.NewGroupTaskStarted: groupTasksContext.setGroupTasks((arr) => [...arr, body]); @@ -955,6 +944,20 @@ export function handleWebSocketMessage( description: `You can now continue with the work`, }); break; + case ReceivedMessagesCommands.UpdateUsers: + 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; default: console.error("unknown command", cmd); break; diff --git a/src/Pages/AdminArea/Roles/index.js b/src/Pages/AdminArea/Roles/index.js index b61e83d..0dd9ee9 100644 --- a/src/Pages/AdminArea/Roles/index.js +++ b/src/Pages/AdminArea/Roles/index.js @@ -12,12 +12,7 @@ import { Typography, notification, } from "antd"; -import { - Constants, - SentMessagesCommands, - hasPermission, - myFetch, -} from "../../../utils"; +import { Constants, hasPermission, myFetch } from "../../../utils"; import { ArrowDownOutlined, ArrowUpOutlined, @@ -34,6 +29,7 @@ import { MyAvatar } from "../../../Components/MyAvatar"; import { useAdminAreaRolesContext } from "../../../Contexts/AdminAreaRolesContext"; import { useWebSocketContext } from "../../../Contexts/WebSocketContext"; import { useAppContext } from "../../../Contexts/AppContext"; +import { SentMessagesCommands } from "../../../Handlers/WebSocketMessageHandler"; const { useBreakpoint } = Grid; diff --git a/src/Pages/AllUsers/CreateUserModal.js b/src/Pages/AllUsers/CreateUserModal.js index 475dbd2..f7e2a3b 100644 --- a/src/Pages/AllUsers/CreateUserModal.js +++ b/src/Pages/AllUsers/CreateUserModal.js @@ -1,15 +1,11 @@ import { Form, Input, Select } from "antd"; import Modal from "antd/es/modal/Modal"; -import { - Constants, - EncodeStringToBase64, - SentMessagesCommands, - isEmailValid, -} from "../../utils"; +import { Constants, EncodeStringToBase64, isEmailValid } from "../../utils"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import { useWebSocketContext } from "../../Contexts/WebSocketContext"; import { useUsersContext } from "../../Contexts/UsersContext"; +import { SentMessagesCommands } from "../../Handlers/WebSocketMessageHandler"; export default function CreateUserModal({ isModalOpen, setIsModalOpen }) { const webSocketContext = useWebSocketContext(); diff --git a/src/Pages/AllUsers/index.js b/src/Pages/AllUsers/index.js index 54eec58..7c70012 100644 --- a/src/Pages/AllUsers/index.js +++ b/src/Pages/AllUsers/index.js @@ -11,7 +11,6 @@ import { import { Constants, FormatDatetime, - SentMessagesCommands, getConnectionStatusItem, hasOnePermission, hasPermission, @@ -26,6 +25,7 @@ import { MyAvatar } from "../../Components/MyAvatar"; import { useUsersContext } from "../../Contexts/UsersContext"; import { useAppContext } from "../../Contexts/AppContext"; import { useWebSocketContext } from "../../Contexts/WebSocketContext"; +import { SentMessagesCommands } from "../../Handlers/WebSocketMessageHandler"; export default function AllUsers() { const webSocketContext = useWebSocketContext(); diff --git a/src/Pages/GroupTasks/Overview/GroupTasksTableList.js b/src/Pages/GroupTasks/Overview/GroupTasksTableList.js index 9df060d..2f152c9 100644 --- a/src/Pages/GroupTasks/Overview/GroupTasksTableList.js +++ b/src/Pages/GroupTasks/Overview/GroupTasksTableList.js @@ -19,7 +19,6 @@ import { Constants, FormatDatetime, GetDuration, - SentMessagesCommands, hasOneXYPermission, hasXYPermission, } from "../../../utils"; @@ -27,6 +26,7 @@ import { useTranslation } from "react-i18next"; import { MyAvatar } from "../../../Components/MyAvatar"; import { useWebSocketContext } from "../../../Contexts/WebSocketContext"; import { useAppContext } from "../../../Contexts/AppContext"; +import { SentMessagesCommands } from "../../../Handlers/WebSocketMessageHandler"; const { useBreakpoint } = Grid; diff --git a/src/Pages/GroupTasks/Overview/GroupTasksViewModal.js b/src/Pages/GroupTasks/Overview/GroupTasksViewModal.js index ae1e9c2..d7f0170 100644 --- a/src/Pages/GroupTasks/Overview/GroupTasksViewModal.js +++ b/src/Pages/GroupTasks/Overview/GroupTasksViewModal.js @@ -15,7 +15,6 @@ import { useNavigate, useParams } from "react-router-dom"; import { Constants, FormatDatetime, - SentMessagesCommands, GetDuration, getUserId, GroupTasksStepsLockedAndUserUpdateInputValueRememberId, @@ -38,6 +37,7 @@ import MyAttachments from "../../../Components/MyAttachments"; import { useWebSocketContext } from "../../../Contexts/WebSocketContext"; import { useGroupTasksContext } from "../../../Contexts/GroupTasksContext"; import { useAppContext } from "../../../Contexts/AppContext"; +import { SentMessagesCommands } from "../../../Handlers/WebSocketMessageHandler"; export default function GroupTasksViewModal({ isOpen }) { const webSocketContext = useWebSocketContext(); diff --git a/src/Pages/GroupTasks/Overview/GroupTypeSelectionModal.js b/src/Pages/GroupTasks/Overview/GroupTypeSelectionModal.js index d7db552..71167b8 100644 --- a/src/Pages/GroupTasks/Overview/GroupTypeSelectionModal.js +++ b/src/Pages/GroupTasks/Overview/GroupTypeSelectionModal.js @@ -10,12 +10,13 @@ import { Tag, notification, } from "antd"; -import { SentMessagesCommands, GetUuid } from "../../../utils"; +import { 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"; +import { SentMessagesCommands } from "../../../Handlers/WebSocketMessageHandler"; export default function GroupTypeSelectionModal({ isOpen, diff --git a/src/Pages/GroupTasks/Overview/index.js b/src/Pages/GroupTasks/Overview/index.js index 195a634..69752a8 100644 --- a/src/Pages/GroupTasks/Overview/index.js +++ b/src/Pages/GroupTasks/Overview/index.js @@ -3,12 +3,7 @@ import { useEffect, useRef, useState } from "react"; import GroupTasksViewModal from "./GroupTasksViewModal"; import GroupTypeSelectionModal from "./GroupTypeSelectionModal"; import GroupTaskTableList from "./GroupTasksTableList"; -import { - Constants, - SentMessagesCommands, - hasPermission, - myFetch, -} from "../../../utils"; +import { Constants, hasPermission, myFetch } from "../../../utils"; import { useTranslation } from "react-i18next"; import { ReloadOutlined } from "@ant-design/icons"; import { useGroupTasksContext } from "../../../Contexts/GroupTasksContext"; @@ -16,6 +11,7 @@ import { useAppContext } from "../../../Contexts/AppContext"; import { useWebSocketContext } from "../../../Contexts/WebSocketContext"; import { useParams } from "react-router-dom"; import MyPagination from "../../../Components/MyPagination"; +import { SentMessagesCommands } from "../../../Handlers/WebSocketMessageHandler"; export default function GroupTasks({ isGroupTasksViewModalOpen }) { const webSocketContext = useWebSocketContext(); @@ -31,6 +27,7 @@ export default function GroupTasks({ isGroupTasksViewModalOpen }) { const { t } = useTranslation(); const [paginationPage, setPaginationPage] = useState(1); const totalPages = useRef(0); + const previousParamCategory = useRef(null); const showGroupTypeSelectionModal = (categoryGroup) => { setCurrentCategoryGroup(categoryGroup); @@ -62,10 +59,24 @@ export default function GroupTasks({ isGroupTasksViewModalOpen }) { }; useEffect(() => { - if (paginationPage === 1) { - fetchGroupTasks(1); + // initially previousParamCategory.current is null on first render + if (previousParamCategory.current === null) { + previousParamCategory.current = paramCategory; + return; + } + + if (paramCategory !== previousParamCategory.current) { + previousParamCategory.current = paramCategory; + + if (paginationPage === 1) { + // if we are on page 1, we need to fetch the new category group + fetchGroupTasks(1); + } else { + // if we are not on page 1, we need to reset the page to 1 and this will trigger the useEffect below + setPaginationPage(1); + } } else { - setPaginationPage(1); + fetchGroupTasks(paginationPage); } }, [paramCategory]); diff --git a/src/Pages/UserProfile/index.js b/src/Pages/UserProfile/index.js index dd996f5..448d594 100644 --- a/src/Pages/UserProfile/index.js +++ b/src/Pages/UserProfile/index.js @@ -19,7 +19,6 @@ import { Constants, EncodeStringToBase64, FormatDatetime, - SentMessagesCommands, getConnectionStatusItem, getUserSessionFromLocalStorage, hasPermission, @@ -40,6 +39,7 @@ import { useUserProfileContext } from "../../Contexts/UserProfileContext"; import { useWebSocketContext } from "../../Contexts/WebSocketContext"; import { useAppContext } from "../../Contexts/AppContext"; import { useSideBarContext } from "../../Contexts/SideBarContext"; +import { SentMessagesCommands } from "../../Handlers/WebSocketMessageHandler"; export default function UserProfile() { const webSocketContext = useWebSocketContext(); diff --git a/src/utils.js b/src/utils.js index bdc73fe..5e795a3 100644 --- a/src/utils.js +++ b/src/utils.js @@ -49,6 +49,11 @@ export const Constants = { EQUIPMENT_DOCUMENTATION_VIEW: "/equipment-documentation/", GROUP_TASKS: "/group-tasks/", GROUP_TASKS_HISTORY: "/group-tasks-history", + USERS: "/users", + SCANNERS: "/scanners", + USER_PROFILE: "/user-profile", + ADMIN_AREA_ROLES: "/admin-area/roles", + ADMIN_AREA_LOGS: "/admin-area/logs", }, GROUP_TASKS_STATUS: { FINISHED: 1, @@ -224,6 +229,7 @@ let webSocketContextPreview = { //export const WebSocketContext = createContext(webSocketContextPreview); +/* // commands received from the backend server export const ReceivedMessagesCommands = { InitUserSocketConnection: 1, @@ -290,7 +296,7 @@ export const SentMessagesCommands = { DeleteUserApiKey: 20, GroupTasksInstallPythonPackages: 21, GroupTasksInstallGlobalPythonPackages: 22, -}; +}; */ /* export function WebSocketProvider({ children,