import React, { useState, useEffect } from 'react'
import { Routes, Route, Link, useLocation } from 'react-router-dom'
import { useQuery } from '@tanstack/react-query'
import {
Server,
Activity,
Terminal,
Globe,
Users,
Database,
Settings,
Monitor,
Minimize2,
Square,
X,
Download,
Maximize2
} from 'lucide-react'
import Overview from './components/Overview'
import Sessions from './components/Sessions'
import ToolCalls from './components/ToolCalls'
import BrowserSessions from './components/BrowserSessions'
import ServerHealth from './components/ServerHealth'
// API functions
const fetchServerHealth = async () => {
const response = await fetch('/health')
if (!response.ok) throw new Error('Failed to fetch server health')
return response.json()
}
function App() {
const location = useLocation()
const [isStandalone, setIsStandalone] = useState(false)
const [showInstallButton, setShowInstallButton] = useState(false)
const [canInstall, setCanInstall] = useState(false)
const [isMaximized, setIsMaximized] = useState(false)
const { data: health, isError } = useQuery({
queryKey: ['health'],
queryFn: fetchServerHealth,
refetchInterval: 5000
})
useEffect(() => {
// Check if running as PWA
const checkStandalone = () => {
const standalone = window.matchMedia('(display-mode: standalone)').matches ||
(window.navigator as any).standalone ||
document.referrer.includes('android-app://');
setIsStandalone(standalone);
};
checkStandalone();
window.matchMedia('(display-mode: standalone)').addListener(checkStandalone);
// Check for PWA install capability
const handleBeforeInstallPrompt = (e: Event) => {
e.preventDefault();
setCanInstall(true);
setShowInstallButton(true);
};
window.addEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
window.addEventListener('appinstalled', () => {
setCanInstall(false);
setShowInstallButton(false);
});
return () => {
window.removeEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
};
}, []);
const handleInstallPWA = () => {
const deferredPrompt = (window as any).deferredPrompt;
if (deferredPrompt) {
deferredPrompt.prompt();
deferredPrompt.userChoice.then((choiceResult: any) => {
if (choiceResult.outcome === 'accepted') {
console.log('PWA installation accepted');
}
setShowInstallButton(false);
(window as any).deferredPrompt = null;
});
}
};
const handleWindowControl = (action: 'minimize' | 'maximize' | 'close') => {
if ('windowControlsOverlay' in navigator) {
switch (action) {
case 'minimize':
// On desktop PWAs, this would minimize the window
console.log('Minimize window');
break;
case 'maximize':
setIsMaximized(!isMaximized);
if (document.fullscreenElement) {
document.exitFullscreen();
} else {
document.documentElement.requestFullscreen();
}
break;
case 'close':
window.close();
break;
}
}
};
const navigation = [
{ name: 'Overview', href: '/', icon: Monitor, current: location.pathname === '/' },
{ name: 'Sessions', href: '/sessions', icon: Users, current: location.pathname === '/sessions' },
{ name: 'Browser', href: '/browser', icon: Globe, current: location.pathname === '/browser' },
{ name: 'Tool Calls', href: '/tools', icon: Terminal, current: location.pathname === '/tools' },
{ name: 'Health', href: '/health', icon: Activity, current: location.pathname === '/health' },
]
return (
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 flex flex-col">
{/* Custom Title Bar (PWA Mode) */}
{isStandalone && (
<div
id="titlebar"
className="drag-region h-12 bg-gray-900 dark:bg-gray-950 flex items-center justify-between px-4 select-none relative"
style={{
background: 'linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%)'
}}
>
{/* Left side - App info */}
<div className="flex items-center space-x-3">
<Server className="h-5 w-5 text-white" />
<span className="text-white font-medium text-sm">MCP Fullstack Dashboard</span>
</div>
{/* Center - Status */}
<div className="no-drag flex items-center">
<div className={`flex items-center px-2 py-1 rounded-full text-xs font-medium ${
isError
? 'bg-red-500/20 text-red-200 border border-red-500/30'
: health?.status === 'ok'
? 'bg-green-500/20 text-green-200 border border-green-500/30'
: 'bg-yellow-500/20 text-yellow-200 border border-yellow-500/30'
}`}>
<div className={`w-1.5 h-1.5 rounded-full mr-1.5 ${
isError
? 'bg-red-400'
: health?.status === 'ok'
? 'bg-green-400'
: 'bg-yellow-400'
}`} />
{isError ? 'Offline' : health?.status || 'Unknown'}
</div>
</div>
{/* Right side - Window controls and install */}
<div className="no-drag flex items-center space-x-2">
{showInstallButton && (
<button
onClick={handleInstallPWA}
className="p-1.5 rounded hover:bg-white/10 transition-colors"
title="Install App"
>
<Download className="h-4 w-4 text-white" />
</button>
)}
<button
onClick={() => handleWindowControl('minimize')}
className="p-1.5 rounded hover:bg-white/10 transition-colors"
title="Minimize"
>
<Minimize2 className="h-4 w-4 text-white" />
</button>
<button
onClick={() => handleWindowControl('maximize')}
className="p-1.5 rounded hover:bg-white/10 transition-colors"
title={isMaximized ? 'Restore' : 'Maximize'}
>
{isMaximized ? (
<Square className="h-4 w-4 text-white" />
) : (
<Maximize2 className="h-4 w-4 text-white" />
)}
</button>
<button
onClick={() => handleWindowControl('close')}
className="p-1.5 rounded hover:bg-red-500/20 transition-colors"
title="Close"
>
<X className="h-4 w-4 text-white" />
</button>
</div>
</div>
)}
{/* Navigation */}
<nav className="bg-white dark:bg-gray-800 shadow-sm border-b dark:border-gray-700 flex-shrink-0">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between h-16">
<div className="flex">
{!isStandalone && (
<div className="flex-shrink-0 flex items-center">
<Server className="h-8 w-8 text-indigo-600" />
<span className="ml-2 text-xl font-semibold text-gray-900 dark:text-white">
MCP Fullstack
</span>
</div>
)}
<div className={`${!isStandalone ? 'ml-6' : ''} flex space-x-8`}>
{navigation.map((item) => (
<Link
key={item.name}
to={item.href}
className={`inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium transition-colors ${
item.current
? 'border-indigo-500 text-gray-900 dark:text-white'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-300 dark:hover:text-white'
}`}
>
<item.icon className="w-4 h-4 mr-2" />
{item.name}
</Link>
))}
</div>
</div>
<div className="flex items-center space-x-4">
{!isStandalone && showInstallButton && (
<button
id="install-pwa"
onClick={handleInstallPWA}
className="inline-flex items-center px-3 py-1.5 border border-indigo-300 text-sm font-medium rounded-md text-indigo-700 bg-indigo-50 hover:bg-indigo-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:bg-indigo-900/20 dark:text-indigo-300 dark:border-indigo-700 dark:hover:bg-indigo-800/30 transition-colors"
>
<Download className="w-4 h-4 mr-2" />
Install App
</button>
)}
{!isStandalone && (
<div className={`flex items-center px-3 py-1 rounded-full text-xs font-medium ${
isError
? 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200'
: health?.status === 'ok'
? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200'
: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200'
}`}>
<div className={`w-2 h-2 rounded-full mr-2 ${
isError
? 'bg-red-500'
: health?.status === 'ok'
? 'bg-green-500'
: 'bg-yellow-500'
}`} />
{isError ? 'Offline' : health?.status || 'Unknown'}
</div>
)}
</div>
</div>
</div>
</nav>
{/* Main content */}
<main className="flex-1 max-w-7xl mx-auto w-full py-6 sm:px-6 lg:px-8">
<Routes>
<Route path="/" element={<Overview />} />
<Route path="/sessions" element={<Sessions />} />
<Route path="/browser" element={<BrowserSessions />} />
<Route path="/tools" element={<ToolCalls />} />
<Route path="/health" element={<ServerHealth />} />
</Routes>
</main>
</div>
)
}
export default App