diff --git a/Data/Server/WebUI/src/Admin/Server_Info.jsx b/Data/Server/WebUI/src/Admin/Server_Info.jsx index 975e8dc..f4b7fd9 100644 --- a/Data/Server/WebUI/src/Admin/Server_Info.jsx +++ b/Data/Server/WebUI/src/Admin/Server_Info.jsx @@ -1,11 +1,12 @@ import React, { useEffect, useState } from "react"; import { Paper, Box, Typography } from "@mui/material"; -export default function ServerInfo() { +export default function ServerInfo({ isAdmin = false }) { const [serverTime, setServerTime] = useState(null); const [error, setError] = useState(null); useEffect(() => { + if (!isAdmin) return; let isMounted = true; const fetchTime = async () => { try { @@ -23,7 +24,9 @@ export default function ServerInfo() { fetchTime(); const id = setInterval(fetchTime, 60000); // update once per minute return () => { isMounted = false; clearInterval(id); }; - }, []); + }, [isAdmin]); + + if (!isAdmin) return null; return ( diff --git a/Data/Server/WebUI/src/Admin/User_Management.jsx b/Data/Server/WebUI/src/Admin/User_Management.jsx index 4bf1cef..d28e1de 100644 --- a/Data/Server/WebUI/src/Admin/User_Management.jsx +++ b/Data/Server/WebUI/src/Admin/User_Management.jsx @@ -68,7 +68,7 @@ async function sha512(text) { return arr.map((b) => b.toString(16).padStart(2, "0")).join(""); } -export default function UserManagement() { +export default function UserManagement({ isAdmin = false }) { const [rows, setRows] = useState([]); // {username, display_name, role, last_login} const [orderBy, setOrderBy] = useState("username"); const [order, setOrder] = useState("asc"); @@ -113,7 +113,7 @@ export default function UserManagement() { }, []); useEffect(() => { - fetchUsers(); + if (!isAdmin) return; (async () => { try { const resp = await fetch("/api/auth/me", { credentials: "include" }); @@ -123,7 +123,8 @@ export default function UserManagement() { } } catch {} })(); - }, [fetchUsers]); + fetchUsers(); + }, [fetchUsers, isAdmin]); const handleSort = (col) => { if (orderBy === col) setOrder(order === "asc" ? "desc" : "asc"); @@ -291,6 +292,8 @@ export default function UserManagement() { } }; + if (!isAdmin) return null; + return ( <> diff --git a/Data/Server/WebUI/src/App.jsx b/Data/Server/WebUI/src/App.jsx index e94b2a1..d7866b4 100644 --- a/Data/Server/WebUI/src/App.jsx +++ b/Data/Server/WebUI/src/App.jsx @@ -5,7 +5,7 @@ import React, { useState, useEffect, useCallback, useRef } from "react"; import { ReactFlowProvider } from "reactflow"; import "reactflow/dist/style.css"; import { - CloseAllDialog, CreditsDialog, RenameTabDialog, TabContextMenu + CloseAllDialog, CreditsDialog, RenameTabDialog, TabContextMenu, NotAuthorizedDialog } from "./Dialogs"; import NavigationSidebar from "./Navigation_Sidebar"; @@ -104,6 +104,7 @@ export default function App() { const [userRole, setUserRole] = useState(null); const [editingJob, setEditingJob] = useState(null); const [jobsRefreshToken, setJobsRefreshToken] = useState(0); + const [notAuthorizedOpen, setNotAuthorizedOpen] = useState(false); // Build breadcrumb items for current view const breadcrumbs = React.useMemo(() => { @@ -383,6 +384,15 @@ export default function App() { [tabs, activeTabId] ); + const isAdmin = (String(userRole || '').toLowerCase() === 'admin'); + + useEffect(() => { + if (!isAdmin && (currentPage === 'admin_users' || currentPage === 'server_info')) { + setNotAuthorizedOpen(true); + setCurrentPage('devices'); + } + }, [currentPage, isAdmin]); + const renderMainContent = () => { switch (currentPage) { case "sites": @@ -496,10 +506,10 @@ export default function App() { return ; case "admin_users": - return ; + return ; case "server_info": - return ; + return ; case "workflow-editor": return ( @@ -647,7 +657,7 @@ export default function App() { - + {renderMainContent()} @@ -668,6 +678,7 @@ export default function App() { onRename={handleRenameTab} onCloseTab={handleCloseTab} /> + setNotAuthorizedOpen(false)} /> ); } diff --git a/Data/Server/WebUI/src/Dialogs.jsx b/Data/Server/WebUI/src/Dialogs.jsx index 49aed0b..d28529e 100644 --- a/Data/Server/WebUI/src/Dialogs.jsx +++ b/Data/Server/WebUI/src/Dialogs.jsx @@ -30,6 +30,26 @@ export function CloseAllDialog({ open, onClose, onConfirm }) { ); } +export function NotAuthorizedDialog({ open, onClose }) { + return ( + + Not Authorized + + + You are not authorized to access this section. + + + + + + + ); +} + export function CreditsDialog({ open, onClose }) { return (