This commit is contained in:
Constantin
2025-09-12 23:04:52 +03:00
commit 2277b11563
127 changed files with 23640 additions and 0 deletions
+164
View File
@@ -0,0 +1,164 @@
import { useState, useEffect } from 'react';
import { Activity, Clock, FileText, AlertTriangle } from 'lucide-react';
import { monitoringAPI } from '../services/api';
function Logs() {
const [backendLog, setBackendLog] = useState('');
const [healthHistory, setHealthHistory] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [tab, setTab] = useState('logs');
useEffect(() => {
fetchData();
}, []);
const fetchData = async () => {
setIsLoading(true);
try {
const [logRes, healthRes] = await Promise.all([
monitoringAPI.getBackendLogs(100),
monitoringAPI.getHealthHistory(),
]);
setBackendLog(logRes.data.log || '');
setHealthHistory(healthRes.data || []);
} catch (error) {
console.error('Failed to fetch monitoring data:', error);
} finally {
setIsLoading(false);
}
};
if (isLoading) {
return (
<div className="flex items-center justify-center h-64">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary-600"></div>
</div>
);
}
return (
<div>
<div className="mb-8">
<h1 className="text-2xl font-bold text-gray-900">System Monitoring</h1>
<p className="mt-2 text-gray-600">
View backend logs and health history
</p>
</div>
<div className="mb-4 flex gap-4">
<button
className={`px-4 py-2 rounded ${tab === 'logs' ? 'bg-primary-600 text-white' : 'bg-gray-200 text-gray-800'}`}
onClick={() => setTab('logs')}
>
<FileText className="inline-block mr-2" /> Backend Logs
</button>
<button
className={`px-4 py-2 rounded ${tab === 'health' ? 'bg-primary-600 text-white' : 'bg-gray-200 text-gray-800'}`}
onClick={() => setTab('health')}
>
<Clock className="inline-block mr-2" /> Health History
</button>
</div>
{tab === 'logs' && (
<div className="card">
<div className="flex items-center mb-4">
<FileText className="h-6 w-6 text-primary-500 mr-2" />
<h3 className="text-lg font-medium text-gray-900">Backend Logs (last 100 lines)</h3>
</div>
<div className="bg-gray-900 text-green-400 p-4 rounded-lg font-mono text-sm h-96 overflow-y-auto">
<pre>{backendLog || 'No logs available.'}</pre>
</div>
</div>
)}
{tab === 'health' && (
<div className="card">
<div className="flex items-center mb-4">
<Clock className="h-6 w-6 text-primary-500 mr-2" />
<h3 className="text-lg font-medium text-gray-900">Health History (last 100 checks)</h3>
</div>
<div className="overflow-x-auto">
<table className="min-w-full text-sm">
<thead>
<tr className="bg-gray-100">
<th className="px-2 py-1 text-left">Timestamp</th>
<th className="px-2 py-1 text-left">Network</th>
<th className="px-2 py-1 text-left">WireGuard</th>
<th className="px-2 py-1 text-left">Email</th>
<th className="px-2 py-1 text-left">Calendar</th>
<th className="px-2 py-1 text-left">Files</th>
<th className="px-2 py-1 text-left">Routing</th>
<th className="px-2 py-1 text-left">Vault</th>
<th className="px-2 py-1 text-left">Alerts</th>
</tr>
</thead>
<tbody>
{healthHistory.map((h, i) => (
<tr key={i} className={h.alerts && h.alerts.length > 0 ? 'bg-red-100' : ''}>
<td className="px-2 py-1 font-mono">{h.timestamp}</td>
<td className="px-2 py-1">
{h.network?.status === 'online' || h.network?.running === true ?
<span className="text-green-600">OK</span> :
<span className="text-red-600 font-bold">Down</span>
}
</td>
<td className="px-2 py-1">
{h.wireguard?.status === 'online' || h.wireguard?.running === true ?
<span className="text-green-600">OK</span> :
<span className="text-red-600 font-bold">Down</span>
}
</td>
<td className="px-2 py-1">
{h.email?.status === 'online' || h.email?.running === true ?
<span className="text-green-600">OK</span> :
<span className="text-red-600 font-bold">Down</span>
}
</td>
<td className="px-2 py-1">
{h.calendar?.status === 'online' || h.calendar?.running === true ?
<span className="text-green-600">OK</span> :
<span className="text-red-600 font-bold">Down</span>
}
</td>
<td className="px-2 py-1">
{h.files?.status === 'online' || h.files?.running === true ?
<span className="text-green-600">OK</span> :
<span className="text-red-600 font-bold">Down</span>
}
</td>
<td className="px-2 py-1">
{h.routing?.status === 'online' || h.routing?.running === true ?
<span className="text-green-600">OK</span> :
<span className="text-red-600 font-bold">Down</span>
}
</td>
<td className="px-2 py-1">
{h.vault?.status === 'online' || h.vault?.running === true ?
<span className="text-green-600">OK</span> :
<span className="text-red-600 font-bold">Down</span>
}
</td>
<td className="px-2 py-1">
{h.alerts && h.alerts.length > 0 ? (
<div className="flex flex-col gap-1">
{h.alerts.map((a, j) => (
<span key={j} className="text-red-700 font-semibold flex items-center"><AlertTriangle className="inline-block h-4 w-4 mr-1 text-red-500" />{a}</span>
))}
</div>
) : (
<span className="text-green-600">None</span>
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
</div>
);
}
export default Logs;