diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx index 41b30d8c..deed7060 100644 --- a/frontend/src/components/Layout.tsx +++ b/frontend/src/components/Layout.tsx @@ -5,6 +5,8 @@ import { ThemeToggle } from './ThemeToggle' import { Button } from './ui/Button' import { useAuth } from '../context/AuthContext' import { checkHealth } from '../api/health' +import NotificationCenter from './NotificationCenter' +import SystemStatus from './SystemStatus' interface LayoutProps { children: ReactNode @@ -27,8 +29,7 @@ export default function Layout({ children }: LayoutProps) { { name: 'Remote Servers', path: '/remote-servers', icon: '🖥️' }, { name: 'Certificates', path: '/certificates', icon: '🔒' }, { name: 'Import Caddyfile', path: '/import', icon: '📥' }, - { name: 'Logs', path: '/logs', icon: '📜' }, - { name: 'Settings', path: '/settings', icon: '⚙️' }, + { name: 'Settings', path: '/settings/security', icon: '⚙️' }, ] return ( @@ -37,6 +38,7 @@ export default function Layout({ children }: LayoutProps) {

CPM+

+ + + {isOpen && ( + <> +
setIsOpen(false)} + >
+
+
+

Notifications

+ {unreadCount > 0 && ( + + )} +
+
+ {notifications.length === 0 ? ( +
+ No new notifications +
+ ) : ( + notifications.map((notification) => ( +
+
+ {getIcon(notification.type)} +
+
+

+ {notification.title} +

+

+ {notification.message} +

+

+ {new Date(notification.created_at).toLocaleString()} +

+
+
+ +
+
+ )) + )} +
+
+ + )} +
+ ); +}; + +export default NotificationCenter; diff --git a/frontend/src/components/SystemStatus.tsx b/frontend/src/components/SystemStatus.tsx new file mode 100644 index 00000000..f32b24ae --- /dev/null +++ b/frontend/src/components/SystemStatus.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { useQuery } from '@tanstack/react-query'; +import { checkUpdates } from '../api/system'; +import { ExternalLink, CheckCircle, AlertCircle } from 'lucide-react'; + +const SystemStatus: React.FC = () => { + const { data: updateInfo, isLoading } = useQuery({ + queryKey: ['system-updates'], + queryFn: checkUpdates, + staleTime: 1000 * 60 * 60, // 1 hour + }); + + if (isLoading) return null; + + if (!updateInfo?.available) { + return ( +
+ + Up to date +
+ ); + } + + return ( +
+ + Update available: {updateInfo.latest_version} + + Changelog + +
+ ); +}; + +export default SystemStatus;