diff --git a/frontend/src/components/InlineGroupEdit.jsx b/frontend/src/components/InlineGroupEdit.jsx index 6a7de28..3511c52 100644 --- a/frontend/src/components/InlineGroupEdit.jsx +++ b/frontend/src/components/InlineGroupEdit.jsx @@ -1,5 +1,11 @@ import { Check, ChevronDown, Edit2, X } from "lucide-react"; -import React, { useEffect, useMemo, useRef, useState } from "react"; +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from "react"; const InlineGroupEdit = ({ value, @@ -38,7 +44,7 @@ const InlineGroupEdit = ({ }, [value, isEditing]); // Calculate dropdown position - const calculateDropdownPosition = () => { + const calculateDropdownPosition = useCallback(() => { if (buttonRef.current) { const rect = buttonRef.current.getBoundingClientRect(); setDropdownPosition({ @@ -47,7 +53,7 @@ const InlineGroupEdit = ({ width: rect.width, }); } - }; + }, []); // Close dropdown when clicking outside useEffect(() => { @@ -68,7 +74,7 @@ const InlineGroupEdit = ({ window.removeEventListener("scroll", calculateDropdownPosition); }; } - }, [isOpen]); + }, [isOpen, calculateDropdownPosition]); const handleEdit = () => { if (disabled) return; diff --git a/frontend/src/components/Layout.jsx b/frontend/src/components/Layout.jsx index 182bd41..3359ab2 100644 --- a/frontend/src/components/Layout.jsx +++ b/frontend/src/components/Layout.jsx @@ -29,7 +29,7 @@ import { Wrench, X, } from "lucide-react"; -import React, { useEffect, useRef, useState } from "react"; +import React, { useCallback, useEffect, useRef, useState } from "react"; import { Link, useLocation } from "react-router-dom"; import { useAuth } from "../contexts/AuthContext"; import { useUpdateNotification } from "../contexts/UpdateNotificationContext"; @@ -242,7 +242,7 @@ const Layout = ({ children }) => { }; // Fetch GitHub stars count - const fetchGitHubStars = async () => { + const fetchGitHubStars = useCallback(async () => { try { const response = await fetch( "https://api.github.com/repos/9technologygroup/patchmon.net", @@ -254,7 +254,7 @@ const Layout = ({ children }) => { } catch (error) { console.error("Failed to fetch GitHub stars:", error); } - }; + }, []); // Short format for navigation area const formatRelativeTimeShort = (date) => { @@ -300,7 +300,7 @@ const Layout = ({ children }) => { // Fetch GitHub stars on component mount useEffect(() => { fetchGitHubStars(); - }, []); + }, [fetchGitHubStars]); return (
diff --git a/frontend/src/contexts/AuthContext.jsx b/frontend/src/contexts/AuthContext.jsx index 5794e5a..41cb9eb 100644 --- a/frontend/src/contexts/AuthContext.jsx +++ b/frontend/src/contexts/AuthContext.jsx @@ -26,41 +26,8 @@ export const AuthProvider = ({ children }) => { const [checkingSetup, setCheckingSetup] = useState(true); - // Initialize auth state from localStorage - useEffect(() => { - const storedToken = localStorage.getItem("token"); - const storedUser = localStorage.getItem("user"); - const storedPermissions = localStorage.getItem("permissions"); - - if (storedToken && storedUser) { - try { - setToken(storedToken); - setUser(JSON.parse(storedUser)); - if (storedPermissions) { - setPermissions(JSON.parse(storedPermissions)); - } else { - // Fetch permissions if not stored - fetchPermissions(storedToken); - } - } catch (error) { - console.error("Error parsing stored user data:", error); - localStorage.removeItem("token"); - localStorage.removeItem("user"); - localStorage.removeItem("permissions"); - } - } - setIsLoading(false); - }, []); - - // Refresh permissions when user logs in (no automatic refresh) - useEffect(() => { - if (token && user) { - // Only refresh permissions once when user logs in - refreshPermissions(); - } - }, [token, user]); - - const fetchPermissions = async (authToken) => { + // Define functions first + const fetchPermissions = useCallback(async (authToken) => { try { setPermissionsLoading(true); const response = await fetch("/api/v1/permissions/user-permissions", { @@ -84,15 +51,49 @@ export const AuthProvider = ({ children }) => { } finally { setPermissionsLoading(false); } - }; + }, []); - const refreshPermissions = async () => { + const refreshPermissions = useCallback(async () => { if (token) { const updatedPermissions = await fetchPermissions(token); return updatedPermissions; } return null; - }; + }, [token, fetchPermissions]); + + // Initialize auth state from localStorage + useEffect(() => { + const storedToken = localStorage.getItem("token"); + const storedUser = localStorage.getItem("user"); + const storedPermissions = localStorage.getItem("permissions"); + + if (storedToken && storedUser) { + try { + setToken(storedToken); + setUser(JSON.parse(storedUser)); + if (storedPermissions) { + setPermissions(JSON.parse(storedPermissions)); + } else { + // Use the proper fetchPermissions function + fetchPermissions(storedToken); + } + } catch (error) { + console.error("Error parsing stored user data:", error); + localStorage.removeItem("token"); + localStorage.removeItem("user"); + localStorage.removeItem("permissions"); + } + } + setIsLoading(false); + }, [fetchPermissions]); + + // Refresh permissions when user logs in (no automatic refresh) + useEffect(() => { + if (token && user) { + // Only refresh permissions once when user logs in + refreshPermissions(); + } + }, [token, user, refreshPermissions]); const login = async (username, password) => { try { diff --git a/frontend/src/pages/Hosts.jsx b/frontend/src/pages/Hosts.jsx index f229388..9be58d3 100644 --- a/frontend/src/pages/Hosts.jsx +++ b/frontend/src/pages/Hosts.jsx @@ -1199,6 +1199,7 @@ const Hosts = () => { sortField, sortDirection, searchParams, + hideStale, ]); // Group hosts by selected field diff --git a/frontend/src/pages/Packages.jsx b/frontend/src/pages/Packages.jsx index 63814e9..e0b75fb 100644 --- a/frontend/src/pages/Packages.jsx +++ b/frontend/src/pages/Packages.jsx @@ -186,6 +186,7 @@ const Packages = () => { securityFilter, sortField, sortDirection, + hostFilter, ]); // Get visible columns in order