import { useState, useEffect, useMemo } from 'react'; import { useStore } from '@nanostores/react'; import * as RadixDialog from '@radix-ui/react-dialog'; import { classNames } from '~/shared/utils/classNames'; import { TabManagement } from '~/settings/shared/components/TabManagement'; import { TabTile } from '~/settings/shared/components/TabTile'; import { useFeatures } from '~/shared/hooks/useFeatures'; import { useNotifications } from '~/shared/hooks/useNotifications'; import { useConnectionStatus } from '~/shared/hooks/useConnectionStatus'; import { tabConfigurationStore, resetTabConfiguration } from '~/settings/stores/settings'; import { profileStore } from '~/shared/stores/profile'; import type { TabType, Profile } from './types'; import { TAB_LABELS, DEFAULT_TAB_CONFIG } from './constants'; import { DialogTitle } from '~/shared/components/ui/Dialog'; import { AvatarDropdown } from './AvatarDropdown'; import BackgroundRays from '~/shared/components/ui/BackgroundRays'; // Import tab content components import ProfileTab from '~/settings/tabs/profile/ProfileTab'; import SettingsTab from '~/settings/tabs/settings/SettingsTab'; import NotificationsTab from '~/settings/tabs/notifications/NotificationsTab'; import FeaturesTab from '~/settings/tabs/features/FeaturesTab'; import { DataTab } from '~/settings/tabs/data/DataTab'; import ConnectionsTab from '~/settings/tabs/connections/ConnectionsTab'; import LocalProvidersTab from '~/settings/tabs/providers/local/LocalProvidersTab'; import CloudProvidersTab from '~/settings/tabs/providers/cloud/CloudProvidersTab'; interface ControlPanelProps { open: boolean; onClose: () => void; } const TAB_DESCRIPTIONS: Record = { profile: 'Manage your profile and account settings', settings: 'Configure application preferences', notifications: 'View and manage your notifications', features: 'Explore new and upcoming features', data: 'Manage your data and storage', 'cloud-providers': 'Configure cloud AI providers and models', 'local-providers': 'Configure local AI providers and models', connection: 'Check connection status and settings', }; // Beta status for experimental features const BETA_TABS = new Set(['local-providers']); const BetaLabel = () => (
BETA
); // Add this function to render tab content const renderTabContent = (activeTab: TabType) => { switch (activeTab) { case 'profile': return ; case 'settings': return ; case 'notifications': return ; case 'features': return ; case 'data': return ; case 'connection': return ; case 'cloud-providers': return ; case 'local-providers': return ; default: return null; } }; export const ControlPanel = ({ open, onClose }: ControlPanelProps) => { // State const [activeTab, setActiveTab] = useState(null); const [loadingTab, setLoadingTab] = useState(null); const [showTabManagement, setShowTabManagement] = useState(false); // Store values const tabConfiguration = useStore(tabConfigurationStore); const profile = useStore(profileStore) as Profile; // Status hooks const { hasNewFeatures, unviewedFeatures, acknowledgeAllFeatures } = useFeatures(); const { hasUnreadNotifications, unreadNotifications, markAllAsRead } = useNotifications(); const { hasConnectionIssues, currentIssue, acknowledgeIssue } = useConnectionStatus(); // Memoize the base tab configurations to avoid recalculation const baseTabConfig = useMemo(() => { return new Map(DEFAULT_TAB_CONFIG.map((tab) => [tab.id, tab])); }, []); // Add visibleTabs logic using useMemo with optimized calculations const visibleTabs = useMemo(() => { if (!tabConfiguration?.userTabs || !Array.isArray(tabConfiguration.userTabs)) { console.warn('Invalid tab configuration, resetting to defaults'); resetTabConfiguration(); return []; } const notificationsDisabled = profile?.preferences?.notifications === false; // Optimize user mode tab filtering return tabConfiguration.userTabs .filter((tab) => { if (!tab?.id) { return false; } if (tab.id === 'notifications' && notificationsDisabled) { return false; } return tab.visible && tab.window === 'user'; }) .sort((a, b) => a.order - b.order); }, [tabConfiguration, profile?.preferences?.notifications, baseTabConfig]); // Reset to default view when modal opens/closes useEffect(() => { if (!open) { // Reset when closing setActiveTab(null); setLoadingTab(null); setShowTabManagement(false); } else { // When opening, set to null to show the main view setActiveTab(null); } }, [open]); // Handle closing const handleClose = () => { setActiveTab(null); setLoadingTab(null); setShowTabManagement(false); onClose(); }; // Handlers const handleBack = () => { if (showTabManagement) { setShowTabManagement(false); } else if (activeTab) { setActiveTab(null); } }; const getTabUpdateStatus = (tabId: TabType): boolean => { switch (tabId) { case 'features': return hasNewFeatures; case 'notifications': return hasUnreadNotifications; case 'connection': return hasConnectionIssues; default: return false; } }; const getStatusMessage = (tabId: TabType): string => { switch (tabId) { case 'features': return `${unviewedFeatures.length} new feature${unviewedFeatures.length === 1 ? '' : 's'} to explore`; case 'notifications': return `${unreadNotifications.length} unread notification${unreadNotifications.length === 1 ? '' : 's'}`; case 'connection': return currentIssue === 'disconnected' ? 'Connection lost' : currentIssue === 'high-latency' ? 'High latency detected' : 'Connection issues detected'; default: return ''; } }; const handleTabClick = (tabId: TabType) => { setLoadingTab(tabId); setActiveTab(tabId); setShowTabManagement(false); // Acknowledge notifications based on tab switch (tabId) { case 'features': acknowledgeAllFeatures(); break; case 'notifications': markAllAsRead(); break; case 'connection': acknowledgeIssue(); break; } // Clear loading state immediately for better responsiveness setTimeout(() => setLoadingTab(null), 100); }; return (
{/* Header */}
{(activeTab || showTabManagement) && ( )} {showTabManagement ? 'Tab Management' : activeTab ? TAB_LABELS[activeTab] : 'Control Panel'}
{/* Avatar and Dropdown */}
{/* Close Button */}
{/* Content */}
{showTabManagement ? ( ) : activeTab ? ( renderTabContent(activeTab) ) : (
{visibleTabs.map((tab, index) => (
handleTabClick(tab.id as TabType)} isActive={activeTab === tab.id} hasUpdate={getTabUpdateStatus(tab.id)} statusMessage={getStatusMessage(tab.id)} description={TAB_DESCRIPTIONS[tab.id]} isLoading={loadingTab === tab.id} className="h-full relative" > {BETA_TABS.has(tab.id) && }
))}
)}
); };