import { Badge } from "antd"; import { useState } from "react"; import { Buffer } from "buffer"; import { v4 as uuidv4 } from "uuid"; /** * constants */ const wssProtocol = window.location.protocol === "https:" ? "wss://" : "ws://"; let apiAddress = ""; let staticContentAddress = ""; let wsAddress = ""; let logApiAddress = ""; let roboticsApiAddress = ""; var roboticsSwaggerAddress = ""; var telegramBotManagerAddress = ""; var telegramBotManagerStaticContentAddress = ""; var crmLinkShareAddress = ""; if (window.location.hostname === "localhost" && window.location.port === "") { // for docker container testing on localhost apiAddress = "http://localhost/api/v1"; staticContentAddress = "http://localhost/api/"; wsAddress = "ws://localhost/ws"; logApiAddress = "http://localhost/lm/v1/log"; roboticsApiAddress = "http://localhost/rcm/v1"; roboticsSwaggerAddress = "http://localhost/rcm/swagger/index.html"; telegramBotManagerAddress = "http://localhost/tm/v1"; telegramBotManagerStaticContentAddress = "http://localhost/tm/"; crmLinkShareAddress = "http://localhost/crm/link/"; } else if (window.location.hostname === "localhost") { // programming on localhost apiAddress = "http://localhost:50050/v1"; staticContentAddress = "http://localhost:50050/"; wsAddress = "ws://localhost:50050/ws"; logApiAddress = "http://127.0.0.1:50110/v1/log"; roboticsApiAddress = "http://localhost:50055/v1"; roboticsSwaggerAddress = "http://localhost:50055/swagger/index.html"; telegramBotManagerAddress = "http://localhost:50056/v1"; telegramBotManagerStaticContentAddress = "http://localhost:50056/"; crmLinkShareAddress = "http://localhost:50050/v1/crm/link/"; /*} else if (window.location.hostname === "192.168.178.93") { apiAddress = "http://192.168.178.93:50050/v1"; staticContentAddress = "http://192.168.178.93:50050/"; wsAddress = "ws://192.168.168.93:50050/ws"; */ } else { // production apiAddress = `${window.location.protocol}//${window.location.hostname}/api/v1`; staticContentAddress = `${window.location.protocol}//${window.location.hostname}/api/`; wsAddress = `${wssProtocol}${window.location.hostname}/ws`; logApiAddress = `${window.location.protocol}//${window.location.hostname}/lm/v1/log`; roboticsApiAddress = `${window.location.protocol}//${window.location.hostname}/rcm/v1`; roboticsSwaggerAddress = `${window.location.protocol}//${window.location.hostname}/rcm/swagger/index.html`; telegramBotManagerAddress = `${window.location.protocol}//${window.location.hostname}/tm/v1`; telegramBotManagerStaticContentAddress = `${window.location.protocol}//${window.location.hostname}/tm/`; crmLinkShareAddress = `${window.location.protocol}//${window.location.hostname}/api/v1/crm/link/`; } export const Constants = { COLORS: { PRIMARY: "#e67e22", SECONDARY: "#9b59b6", ICON_INFO: "#08c", }, TEXT_EMPTY_PLACEHOLDER: "-/-", /*API_ADDRESS: "http://localhost:50050/v1", STATIC_CONTENT_ADDRESS: "http://localhost:50050/", WS_ADDRESS: "ws://localhost:50050/ws", */ /*API_ADDRESS: window.location.protocol + "//" + window.location.hostname + "/api/v1", STATIC_CONTENT_ADDRESS: window.location.protocol + "//" + window.location.hostname + "/api/", WS_ADDRESS: `${wssProtocol}${window.location.hostname}/wsapi`,*/ API_ADDRESS: apiAddress, STATIC_CONTENT_ADDRESS: staticContentAddress, WS_ADDRESS: wsAddress, LOG_API_ADDRESS: logApiAddress, ROBOTICS_API_ADDRESS: roboticsApiAddress, // robot-control-manager ROBOTICS_SWAGGER_ADDRESS: roboticsSwaggerAddress, TELEGRAM_BOT_MANAGER_ADDRESS: telegramBotManagerAddress, TELEGRAM_BOT_MANAGER_CONTENT_ADDRESS: telegramBotManagerStaticContentAddress, CRM_LINK_SHARE_ADDRESS: crmLinkShareAddress, ROUTE_PATHS: { EQUIPMENT_DOCUMENTATION: "/equipment-documentation", EQUIPMENT_DOCUMENTATION_VIEW: "/equipment-documentation/", NO_GROUP_TASKS_AVAILABLE: "/group-tasks-no-available", 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", ADMIN_AREA_MANAGE: "/admin-area/manage", CONSOLES: "/consoles", ROBOTICS_ROBOTS: "/robotics/robots", CRM: "/crm/", CRM_TEST: "/crm/test", CUSTOMERFEEDBACK_VIEW: "/customer-feedback", }, CRM_TYPE: { TEST_CUSTOMERS: "test-customers", CUSTOMERS: "customers", DMC_PIPELINE: "dmc-pipeline", SETTER_CLOSER: "setter-closer", }, GROUP_TASKS_STATUS: { FINISHED: 1, RUNNING: 2, CANCELED: 3, FAILED: 4, INPUT_REQUIRED: 5, PAUSED: 6, UNDO_ENDED: 7, }, GLOBALS: { MIN_USERNAME_LENGTH: 2, MAX_USERNAME_LENGTH: 20, MIN_PASSWORD_LENGTH: 6, MAX_PASSWORD_LENGTH: 64, MIN_ROLE_DISPLAY_NAME: 3, MAX_ROLE_DISPLAY_NAME: 30, MAX_ROLE_DESCRIPTION: 80, MAX_EQUIPMENT_DOCUMENTATION_TITLE_LENGTH: 60, MAX_EQUIPMENT_DOCUMENTATION_NOTE_LENGTH: 2000, EQUIPMENT_DOCUMENTATIONS_PAGINATION_LIMIT: 3, GROUP_TASKS_PAGINATION_LIMIT: 5, NOTIFICATIONS_PAGINATION_LIMIT: 10, MIN_LOG_MANAGER_DISPLAY_NAME_LENGTH: 2, MAX_LOG_MANAGER_DISPLAY_NAME_LENGTH: 16, MIN_LOG_MANAGER_ADDRESS_LENGTH: 3, MAX_LOG_MANAGER_ADDRESS_LENGTH: 100, MIN_ROBOTICS_ROBOT_NAME_LENGTH: 2, MAX_ROBOTICS_ROBOT_NAME_LENGTH: 30, MIN_USER_API_KEY_NAME_LENGTH: 2, MAX_USER_API_KEY_NAME_LENGTH: 30, ROBOTICS_ROBOTS_PAGINATION_LIMIT: 5, ROBOTICS_UNAUTHORIZED_PAGINATION_LIMIT: 5, TELEGRAM_VERIFY_CODE_EXPIRATION_TIME: 10 * 60 * 1000, // 10 minutes }, MAX_AVATAR_SIZE: 5 * 1024 * 1024, ACCEPTED_AVATAR_FILE_TYPES: [ "image/png", "image/jpeg", "image/jpg", "image/gif", ], ACCEPTED_EQUIPMENT_DOCUMENTATION_FILE_TYPES: [ "image/png", "image/jpeg", "image/jpg", ], PERMISSIONS: { EQUIPMENT_DOCUMENTATION: { VIEW: "equipment_documentation.view", CREATE: "equipment_documentation.create", EDIT: "equipment_documentation.edit", }, GROUP_TASKS: { OVERVIEW: { XYNewTask: "group_tasks.overview.XY.new_task", XYReloadGroupConfig: "group_tasks.overview.XY.reload_group_config", XYInstallPythonPackages: "group_tasks.overview.XY.install_python_packages", XYView: "group_tasks.overview.XY.view", }, HISTORY: "group_tasks.history", INSTALL_GLOBAL_PYTHON_PACKAGES: "group_tasks.install_global_python_packages", }, ALL_USERS: { CREATE_NEW_USER: "all_users.create_new_user", ACTION: { CHANGE_ROLE: "all_users.action.change_role", DELETE_USER: "all_users.action.delete_user", USER_DEACTIVATION: "all_users.action.user_deactivation", }, }, ADMIN_AREA: { ROLES: { CREATE_NEW_ROLE: "admin_area.roles.create_new_role", UPDATE_ROLE: "admin_area.roles.update_role", DELETE_ROLE: "admin_area.roles.delete_role", MOVE_ROLE_UP_DOWN: "admin_area.roles.move_role_up_down", }, LOGS: "admin_area.logs", MANAGE: { CHECK_WHICH_CATEGORIES_ARE_AVAILABLE: "admin_area.manage.check_which_categories_are_available", ADD_LOG_MANAGER_SERVER_CONNECTION: "admin_area.manage.add_log_manager_server_connection", REMOVE_LOG_MANAGER_SERVER_CONNECTION: "admin_area.manage.remove_log_manager_server_connection", }, }, USER_PROFILE: { API_KEYS: "user_profile.api_keys", }, CONSOLES: { VIEW: "consoles.view", }, ROBOTICS: { ROBOTS: { VIEW: "robotics.robots.view", VIEW_ROBOTS_ADDRESSES: "robotics.robots.view_robots_addresses", FREE_UP_JOB: "robotics.robots.free_up_job", EDIT_ROBOT_NAME: "robotics.robots.edit_robot_name", DISCONNECT_ROBOT: "robotics.robots.disconnect_robot", ENABLE_PERMIT_JOIN: "robotics.robots.enable_permit_join", AUTHORIZE_DENY_UNAUTHORIZED_ROBOTS: "robotics.robots.authorize_deny_unauthorized_robots", VIEW_SWAGGER_DOCUMENTATION: "robotics.robots.view_swagger_documentation", }, }, CRM: { CUSTOMERS: { VIEW: "crm.customers.view", }, DMC_PIPELINE: { VIEW: "crm.dmc_pipeline.view", }, SETTER_CLOSER: { VIEW: "crm.setter_closer.view", }, }, CUSTOMERFEEDBACK: { VIEW: "customerfeedback.view", }, }, SYSTEM_LOG_TYPE: { INFO: 0, ERROR: 1, }, LOADING: "loading...", }; export const AppStyle = { app: { margin: 12, borderRadius: 12, primary: "#4096ff", }, typography: { text: { marginBottom: 6, }, }, grid: { row: { gutter: [16, 16], }, }, }; export function GetUuid() { return uuidv4(); } /** * user session */ export function UseUserSession() { const getUserSession = () => { return getUserSessionFromLocalStorage(); }; const [userSession, setUserSession] = useState(getUserSession()); const saveUserSession = (session) => { setUserSession(session); if (session === undefined) { localStorage.removeItem("session"); } else { setUserSessionToLocalStorage(session); } }; return { setUserSession: saveUserSession, userSession, }; } export function getUserSessionFromLocalStorage() { return localStorage.getItem("session"); } export function setUserSessionToLocalStorage(session) { localStorage.setItem("session", session); } // needed for a user who uses multiple tabs in the browser // with the same session id because otherwise the last browser // tab would subscribe to the topic and the other tabs would // not receive any messages // used for topic subscribtion and grouptasks export const BrowserTabSession = GetUuid(); export const wsConnectionCustomEventName = "wsConnection"; // used for sideMenu export const BreakpointLgWidth = 992; /** * websocket */ //let l = "loading..."; /* let webSocketContextPreview = { User: { Id: "", Username: l, Email: l, Sessions: [], Permissions: [], RoleId: "", ApiKeys: [], }, AllUsers: [], AllRoles: [], ConnectionBadgeStatus: "error", ConnectedWebSocketUsersCount: 0, CategoryGroups: [], GroupTasks: [], GroupTasksSteps: [], Scanners: [], UserProfileStateUsername: l, UserProfileStateEmail: l, AdminAreaRolesPermissions: [], }; */ //export const WebSocketContext = createContext(webSocketContextPreview); /* // 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 WebSocketProvider({ children, userSession, setUserSession, notificationApi, isReady, setIsReady, }) { //const [isReady, setIsReady] = useState(false); const [connectionBadgeStatus, setConnectionBadgeStatus] = useState( webSocketContextPreview.ConnectionBadgeStatus ); const [connectedWebSocketUsersCount, setConnectedWebSocketUsersCount] = useState(0); const [user, setUser] = useState(webSocketContextPreview.User); const [allUsers, setAllUsers] = useState(webSocketContextPreview.AllUsers); const [allRoles, setAllRoles] = useState(webSocketContextPreview.AllRoles); const [categoryGroups, setCategoryGroups] = useState( webSocketContextPreview.CategoryGroups ); // these are all group tasks that are then filtered and displayed in the respective tables for the category const [groupTasks, setGroupTasks] = useState([]); const [groupTasksSteps, setGroupTasksSteps] = useState([]); const [scanners, setScanners] = useState([]); const navigate = useNavigate(); const StartGroupTasksOpenModalRememberIdRef = useRef(null); const [userProfileStateUsername, setUserProfileStateUsername] = useState( webSocketContextPreview.UserProfileStateUsername ); const [userProfileStateEmail, setUserProfileStateEmail] = useState( webSocketContextPreview.UserProfileStateEmail ); const [adminAreaRolesPermissions, setAdminAreaRolesPermissions] = useState( webSocketContextPreview.AdminAreaRolesPermissions ); const ws = useRef(null); const connect = () => { ws.current = new WebSocket(Constants.WS_ADDRESS + "?auth=" + userSession); ws.current.onopen = () => { console.log("connected"); setConnectionBadgeStatus("success"); setIsReady(true); }; 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.InitUserSocketConnection: if (body.User.Permissions === null) { body.User.Permissions = []; } setUser(body.User); setUserProfileStateEmail(body.User.Email); setUserProfileStateUsername(body.User.Username); setAllUsers(body.AllUsers); setAllRoles(body.AllRoles); if (body.CategoryGroups === null) { body.CategoryGroups = []; } setCategoryGroups(body.CategoryGroups); setGroupTasks(body.GroupTasks); setGroupTasksSteps(body.GroupTasksSteps); if (body.Scanners !== null) setScanners(body.Scanners); if (body.AdminArea.RolesPermissions !== null) setAdminAreaRolesPermissions(body.AdminArea.RolesPermissions); localStorage.setItem("userId", body.User.Id); break; case ReceivedMessagesCommands.UpdateConnectedUsers: setConnectedWebSocketUsersCount(body.WebSocketUsersCount); setAllUsers((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: setGroupTasks((arr) => [...arr, body]); if ( body.RememberId === StartGroupTasksOpenModalRememberIdRef.current ) { navigate(`${Constants.ROUTE_PATHS.GROUP_TASKS}/${body.Id}`); } break; case ReceivedMessagesCommands.NewGroupTaskStep: setGroupTasksSteps((arr) => [...arr, body]); scrollToNextStep(body.GroupTasksId, body.Step); break; case ReceivedMessagesCommands.UpdateGroupTaskStep: setGroupTasksSteps((arr) => { const newArr = [...arr]; newArr[arr.findIndex((arr1) => arr1.Id === body.Id)] = body; return newArr; }); scrollToNextStep(body.GroupTasksId, body.Step); break; case ReceivedMessagesCommands.UpdateGroupTask: setGroupTasks((arr) => { const newArr = [...arr]; newArr[arr.findIndex((arr1) => arr1.Id === body.Id)] = body; return newArr; }); break; case ReceivedMessagesCommands.ReloadingGroupTasks: notificationApi["warning"]({ message: `Group ${body} is reloading`, duration: 2, }); break; case ReceivedMessagesCommands.GroupTasksReloaded: if (body.RemovedCategory !== undefined) { setCategoryGroups((arr) => arr.filter((arr1) => arr1.category !== 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; } setCategoryGroups((arr) => { const newArr = [...arr]; newArr[ arr.findIndex((arr1) => arr1.category === body.Category) ].groups = body.CategoryGroups; return newArr; }); break; case ReceivedMessagesCommands.UpdateUserSessions: setUser((arr) => ({ ...arr, Sessions: body })); break; case ReceivedMessagesCommands.UpdateAllUsersUserAvatar: setAllUsers((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; setGroupTasksSteps((arr) => { const newArr = [...arr]; newArr[ arr.findIndex( (arr1) => arr1.GroupTasksId === body.groupTaskId && arr1.Step === body.step ) ].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 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; setGroupTasksSteps((arr) => { const newArr = [...arr]; newArr[ arr.findIndex( (arr1) => arr1.GroupTasksId === body.GroupTaskId && arr1.Step === body.Step ) ].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) { setUser((user) => { const updatedUser = { ...user }; if (user.Id === body.UserId) { if (body.Changes.Username !== undefined) { updatedUser.Username = body.Changes.Username; setUserProfileStateUsername(body.Changes.Username); } if (body.Changes.Email !== undefined) { updatedUser.Email = body.Changes.Email; setUserProfileStateEmail(body.Changes.Email); } } return updatedUser; }); if (body.Changes.Username !== undefined) { setAllUsers((arr) => { const newArr = [...arr]; newArr[ arr.findIndex((arr1) => arr1.Id === body.UserId) ].Username = body.Changes.Username; return newArr; }); } } break; case ReceivedMessagesCommands.AdminAreaNewRoleCreated: setAllRoles((arr) => [...arr, body]); setAdminAreaRolesPermissions((arr) => [ ...arr, { RoleId: body.Id, Permissions: [] }, ]); break; case ReceivedMessagesCommands.AdminAreaRoleUpdated: setAllRoles((arr) => { const newArr = [...arr]; const arrIndex = arr.findIndex((arr1) => arr1.Id === body.RoleId); if (body.Changes.DisplayName !== undefined) { newArr[arrIndex].DisplayName = body.Changes.DisplayName; } if (body.Changes.Description !== undefined) { newArr[arrIndex].Description = body.Changes.Description; } return newArr; }); if ( body.Changes.AddedPermissions !== undefined || body.Changes.RemovedPermissions !== undefined ) { setAdminAreaRolesPermissions((arr) => { const newArr = [...arr]; const roleIndex = arr.findIndex( (item) => item.RoleId === body.RoleId ); 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: setAllRoles((arr) => { const newArr = [...arr]; const updatedRoleIndex = newArr.findIndex( (role) => role.Id === body.RoleId ); 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: setAllRoles((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; }); setAdminAreaRolesPermissions((arr) => { let newArr = [...arr]; newArr = newArr.filter( (rolePermission) => rolePermission.RoleId !== body.RoleId ); return newArr; }); break; case ReceivedMessagesCommands.AllUsersUserRoleUpdated: setAllUsers((arr) => { const newArr = [...arr]; newArr[newArr.findIndex((user) => user.Id === body.UserId)].RoleId = body.RoleId; return newArr; }); if (body.Permissions !== undefined) { 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 ) { 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; } setAllUsers((arr) => [ ...arr, { Id: body.Id, RoleId: body.RoleId, Username: body.Username, ConnectionStatus: body.ConnectionStatus, Deactivated: body.Deactivated, }, ]); break; case ReceivedMessagesCommands.AllUsersUserDeleted: setAllUsers((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: setAllUsers((arr) => { let newArr = [...arr]; newArr[ newArr.findIndex((user) => user.Id === body.UserId) ].Deactivated = body.Deactivated; return newArr; }); break; case ReceivedMessagesCommands.GroupTasksCategoryGroupChanges: if ( body["AddedPermissions"] !== undefined || body["RemovedPermissions"] !== undefined ) { 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; }); setAdminAreaRolesPermissions((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 ) { 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: setUser((user) => { const updatedUser = { ...user }; updatedUser.ApiKeys.push(body); return updatedUser; }); break; case ReceivedMessagesCommands.DeletedUserApiKey: setUser((user) => { const updatedUser = { ...user }; updatedUser.ApiKeys = updatedUser.ApiKeys.filter( (apiKey) => apiKey.Id !== body ); return updatedUser; }); break; case ReceivedMessagesCommands.NewApiKeyUsageCount: setUser((user) => { const updatedUser = { ...user }; const foundIndex = updatedUser.ApiKeys.findIndex( (apiKey) => apiKey.Id === body.Id ); if (foundIndex !== -1) { updatedUser.ApiKeys[foundIndex].UsageCount = body.UsageCount; updatedUser.ApiKeys[foundIndex].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; } }; ws.current.onclose = (event) => { setIsReady(false); setConnectionBadgeStatus("error"); console.warn("closed", event); // custom code defined by the backend server if (event.code === 4001 || event.code === 4002) { //Unauthorized || SessionClosed setUserSession(); window.location.href = "/"; return; } if (event.reason.code === 1005) return; console.warn("reconnecting..."); setTimeout(() => connect(), 1000); }; }; useEffect(() => { connect(); return () => ws.current.close(); }, []); const SendSocketMessage = (cmd, body) => { if (isReady) { ws.current.send(JSON.stringify({ Cmd: cmd, Body: body })); } else { notificationApi["error"]({ message: `Websocket is not ready`, description: `Please check your internet connection`, }); } }; return ( {children} ); } */ /* function scrollToNextStep(groupTaskId, step) { setTimeout( () => document .getElementById(`${groupTaskId}-scroll-${step - 1}`) ?.scrollIntoView({ behavior: "smooth" }), 200 ); } */ export function FormatDatetime(datetime) { if (datetime === undefined || datetime === "0001-01-01T00:00:00Z") { return Constants.TEXT_EMPTY_PLACEHOLDER; } const date = new Date(datetime); const day = String(date.getDate()).padStart(2, "0"); const month = String(date.getMonth() + 1).padStart(2, "0"); const year = date.getFullYear(); const hours = String(date.getHours()).padStart(2, "0"); const minutes = String(date.getMinutes()).padStart(2, "0"); const seconds = String(date.getSeconds()).padStart(2, "0"); return `${day}.${month}.${year} ${hours}:${minutes}:${seconds}`; } export function GetDuration(startTime, endTime) { if (endTime === "0001-01-01T00:00:00Z") { return Constants.TEXT_EMPTY_PLACEHOLDER; } const diff = Math.abs(new Date(startTime) - new Date(endTime)); if (diff === 0) { return "0ms"; } const milliseconds = diff % 1000; const seconds = Math.floor(diff / 1000); const minutes = Math.floor(seconds / 60); const hours = Math.floor(minutes / 60); const days = Math.floor(hours / 24); let result = ""; if (days > 0) { result += days + "d "; } if (hours > 0) { result += (hours % 24) + "h "; } if (minutes > 0) { result += (minutes % 60) + "m "; } if (seconds > 0) { result += (seconds % 60) + "s "; } if (milliseconds > 0) { result += milliseconds + "ms"; } return result.trim(); } export function getConnectionStatusItem(connectionStatus) { return connectionStatus === 0 ? ( ) : ( ); } /* export function getUserId() { return localStorage.getItem("userId"); } */ const emailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; export function isEmailValid(email) { return emailRegex.test(email); } export function CapitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } export function hasPermission(userPermissions, permission) { if (userPermissions === null) return false; return userPermissions.includes(permission); } export function hasXYPermission(userPermissions, permission, xyValue) { if (userPermissions === null) return false; return userPermissions.includes( permission.replace("XY", xyValue.toLowerCase()) ); } export function hasOnePermission(userPermissions, ...permissions) { if (userPermissions === null) return false; for (const permission of permissions) { if (userPermissions.includes(permission)) { return true; } } return false; } export function hasOneXYPermission(userPermissions, xyValue, ...permissions) { for (const permission of permissions) { if ( userPermissions.includes(permission.replace("XY", xyValue.toLowerCase())) ) { return true; } } return false; } export function EncodeStringToBase64(value) { return Buffer.from(value).toString("base64"); } export function DecodedBase64ToString(value) { return Buffer.from(value, "base64").toString(); } export const myFetchContentType = { JSON: 0, MULTIPART_FORM_DATA: 1, }; export function myFetch( url, method, body = null, headers = {}, contentType = myFetchContentType.JSON, fetchUrl = Constants.API_ADDRESS, ignoreUnauthorized = false ) { const getContentType = () => { if (contentType === myFetchContentType.JSON) return "application/json"; return "multipart/form-data"; }; const getBody = () => { if (!body) return null; if (contentType === myFetchContentType.JSON) return JSON.stringify(body); return body; }; const requestOptions = { method: method, headers: { "X-Authorization": getUserSessionFromLocalStorage(), "Content-Type": getContentType(), ...headers, }, body: getBody(), }; if (fetchUrl === "") { fetchUrl = Constants.API_ADDRESS; } return fetch(`${fetchUrl}${url}`, requestOptions) .then((response) => { // if status is not in range 200-299 if (!response.ok) { if (!ignoreUnauthorized && response.status === 401) { setUserSessionToLocalStorage(""); window.location.href = "/"; } throw response.status; } // check if response is json if (response.headers.get("content-type")?.includes("application/json")) { return response.json(); } return response.text(); }) .catch((error) => { throw error; }); } export function showUnkownErrorNotification(notificationApi, t) { notificationApi["error"]({ message: t("common.request.unknownError.title"), description: t("common.request.unknownError.description"), }); } export function showInputsInvalidNotification(notificationApi, t) { notificationApi["warning"]({ message: t("common.request.inputsInvalid.title"), description: t("common.request.inputsInvalid.description"), }); }