diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index d577d2c14..bd96277d8 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from 'react';
+import React, { useState, useEffect, Suspense, lazy } from 'react';
import {
Container,
Box,
@@ -12,172 +12,72 @@ import {
Button,
Link,
Chip,
- Alert
+ Alert,
+ Menu,
+ MenuItem,
+ ListItemIcon,
+ ListItemText,
+ Switch,
+ Divider
} from '@mui/material';
import { useTheme } from '@mui/material/styles';
import Brightness4Icon from '@mui/icons-material/Brightness4';
import Brightness7Icon from '@mui/icons-material/Brightness7';
import GitHubIcon from '@mui/icons-material/GitHub';
+import SettingsIcon from '@mui/icons-material/Settings';
+import ViewCompactIcon from '@mui/icons-material/ViewCompact';
import NetworkDisplay from './components/NetworkDisplay';
import { AppThemeProvider, useThemeContext } from './context/ThemeContext';
+import { SearchProvider } from './context/SearchContext';
+import { UserSettingsProvider, useUserSettings } from './context/UserSettingsContext';
+import SearchField from './components/SearchField';
import useSocket from './hooks/useSocket';
import { VERSION } from './utils/version';
import { AnimatedLogoWithText } from './components/network/UIComponents';
import { initializeStorage } from './utils/storageUtils';
+import { SnackbarProvider } from 'notistack';
function AppContent() {
- const { darkMode, toggleDarkMode } = useThemeContext();
- const [selectedNode, setSelectedNode] = useState('all');
- const [hasError, setHasError] = useState(false);
- const [errorMessage, setErrorMessage] = useState('');
-
- // Check if we're in development mode - moved up to fix initialization order
- const isDevelopment = import.meta.env.DEV;
-
- // Error boundary effect
+ // Initialize local storage with default values if needed
useEffect(() => {
- const handleError = (event) => {
- console.error('Global error caught:', event.error);
- setHasError(true);
- setErrorMessage(event.error?.message || 'An unknown error occurred');
- };
-
- window.addEventListener('error', handleError);
-
- return () => {
- window.removeEventListener('error', handleError);
- };
+ initializeStorage();
}, []);
- // Initialize storage based on environment
- useEffect(() => {
- // Only initialize mock data flags if in development mode and not explicitly disabled
- if (isDevelopment && import.meta.env.DISABLE_MOCK_DATA !== 'true') {
- console.log('Development mode detected, mock data can be enabled if needed');
- } else {
- // In production or when explicitly disabled, ensure mock data is disabled
- if (localStorage.getItem('use_mock_data') === 'true' || localStorage.getItem('MOCK_DATA_ENABLED') === 'true') {
- console.log('Resetting mock data flags to match production environment');
- localStorage.removeItem('use_mock_data');
- localStorage.removeItem('MOCK_DATA_ENABLED');
- }
- }
- }, [isDevelopment]);
-
- const {
- nodeData,
- guestData,
- isConnected,
- isMockData,
- processedMetricsData,
- forceUpdateCounter
- } = useSocket();
const theme = useTheme();
+ const { status, connected } = useSocket();
- // Force a re-render when the forceUpdateCounter changes
- useEffect(() => {
- if (forceUpdateCounter % 10 === 0 && forceUpdateCounter > 0) {
- console.log('Force update triggered by counter:', forceUpdateCounter);
- }
- }, [forceUpdateCounter]);
+ // Get theme context functions
+ const { darkMode, toggleDarkMode } = useUserSettings();
- // Check if mock data is enabled - using both localStorage values and socket status
- const isMockDataEnabled = isMockData ||
- localStorage.getItem('use_mock_data') === 'true' ||
- localStorage.getItem('MOCK_DATA_ENABLED') === 'true';
+ // Get user settings
+ const { compactMode, toggleCompactMode } = useUserSettings();
- // Initialize storage and check for environment changes
- useEffect(() => {
- const wasCleared = initializeStorage();
- if (wasCleared) {
- console.log('Application data was cleared due to environment change');
- }
- }, []);
+ // State for settings menu
+ const [settingsAnchorEl, setSettingsAnchorEl] = useState(null);
+ const isSettingsMenuOpen = Boolean(settingsAnchorEl);
- // Add a listener for node change events from the NetworkDisplay component
- useEffect(() => {
- const handleNodeChangeEvent = (event) => {
- if (event.detail && event.detail.node) {
- setSelectedNode(event.detail.node);
- }
- };
-
- window.addEventListener('nodeChange', handleNodeChangeEvent);
-
- // Check URL parameters on initial load
- const urlParams = new URLSearchParams(window.location.search);
- const nodeParam = urlParams.get('node');
- if (nodeParam) {
- setSelectedNode(nodeParam);
- }
-
- return () => {
- window.removeEventListener('nodeChange', handleNodeChangeEvent);
- };
- }, []);
+ // Settings menu handlers
+ const handleSettingsClick = (event) => {
+ setSettingsAnchorEl(event.currentTarget);
+ };
- // If there's an error, show an error message
- if (hasError) {
- return (
-
-
- Something went wrong
-
-
- {errorMessage}
-
-
- Try refreshing the page or check the console for more details.
-
-
-
- );
- }
+ const handleSettingsClose = () => {
+ setSettingsAnchorEl(null);
+ };
+ const [selectedNode, setSelectedNode] = useState('all');
+
+ // Generate content based on connection status
return (
- {
- // Only blur if clicking the container itself, not its children
- if (e.target === e.currentTarget) {
- document.activeElement?.blur();
- }
- }}>
- {/* DEMO MODE Banner - Only visible when mock data is enabled */}
- {(isMockDataEnabled) && (
-
- DEMO MODE - Viewing simulated data. To view real Proxmox data, disable mock data in your .env file.
-
- )}
-
+
@@ -223,12 +123,23 @@ function AppContent() {
- {/* Dark Mode Toggle Button */}
-
+ {/* Search Field */}
+
+
+ {/* Column Visibility Button - Add reference to NetworkDisplay to access this */}
+
+ {/* This Box will be populated by NetworkDisplay with the column visibility button */}
+
+
+ {/* Settings Button */}
+
- {darkMode ? : }
+
+
+ {/* Settings Menu */}
+
{
if (e.target === e.currentTarget) {
@@ -259,7 +240,7 @@ function AppContent() {
}
}}
>
-
+
{/* Network Display Component - pass the selected node as a prop */}
@@ -288,7 +269,13 @@ function AppContent() {
function App() {
return (
-
+
+
+
+
+
+
+
);
}