Fix jwt-token

This commit is contained in:
2025-09-14 18:10:25 +02:00
parent e7ca2ae6b5
commit b6909e9964
2 changed files with 411 additions and 115 deletions

View File

@@ -6,76 +6,166 @@ import {
ServerIcon,
CircleStackIcon,
ShieldCheckIcon,
ClockIcon
ClockIcon,
CpuChipIcon,
ChartBarIcon,
ExclamationTriangleIcon,
CheckCircleIcon,
XCircleIcon
} from '@heroicons/react/24/outline'
const System = () => {
const [systemInfo, setSystemInfo] = useState(null)
const [loading, setLoading] = useState(true)
const [lastUpdate, setLastUpdate] = useState(null)
useEffect(() => {
loadSystemInfo()
const interval = setInterval(loadSystemInfo, 30000) // Update every 30 seconds
return () => clearInterval(interval)
}, [])
const loadSystemInfo = async () => {
try {
setLoading(true)
// Use the management system-info endpoint
if (!loading) setLoading(false) // Don't show loading for refreshes
const response = await api.get('/management/system-info')
setSystemInfo(response.data.data)
setLastUpdate(new Date())
} catch (error) {
// Mock data for development
setSystemInfo({
version: '1.0.0',
environment: 'development',
uptime: '7d 14h 32m',
database: {
status: 'connected',
version: 'PostgreSQL 14.2',
connections: 5,
maxConnections: 100
},
memory: {
used: '256MB',
total: '1GB',
percentage: 25
},
lastBackup: '2024-01-15T10:30:00Z',
ssl: {
status: 'valid',
expiresAt: '2024-03-15T00:00:00Z'
}
})
console.error('Failed to load system info:', error)
toast.error('Failed to load system information')
} finally {
setLoading(false)
}
}
const StatusCard = ({ title, icon: Icon, children }) => (
<div className="bg-white rounded-lg shadow p-6">
<div className="flex items-center mb-4">
<Icon className="h-6 w-6 text-blue-600 mr-2" />
<h3 className="text-lg font-medium text-gray-900">{title}</h3>
</div>
{children}
</div>
)
const StatusIndicator = ({ status }) => {
const colors = {
connected: 'bg-green-100 text-green-800',
valid: 'bg-green-100 text-green-800',
warning: 'bg-yellow-100 text-yellow-800',
error: 'bg-red-100 text-red-800'
const StatusCard = ({ title, icon: Icon, children, status = 'normal' }) => {
const statusColors = {
normal: 'border-gray-200',
warning: 'border-yellow-300 bg-yellow-50',
critical: 'border-red-300 bg-red-50',
success: 'border-green-300 bg-green-50'
}
return (
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${colors[status] || colors.error}`}>
{status.charAt(0).toUpperCase() + status.slice(1)}
<div className={`bg-white rounded-lg shadow border-2 p-6 ${statusColors[status]}`}>
<div className="flex items-center mb-4">
<Icon className="h-6 w-6 text-blue-600 mr-2" />
<h3 className="text-lg font-medium text-gray-900">{title}</h3>
</div>
{children}
</div>
)
}
const StatusIndicator = ({ status, label }) => {
const configs = {
valid: { color: 'bg-green-100 text-green-800', icon: CheckCircleIcon },
warning: { color: 'bg-yellow-100 text-yellow-800', icon: ExclamationTriangleIcon },
critical: { color: 'bg-red-100 text-red-800', icon: XCircleIcon },
error: { color: 'bg-red-100 text-red-800', icon: XCircleIcon },
connected: { color: 'bg-green-100 text-green-800', icon: CheckCircleIcon }
}
const config = configs[status] || configs.error
const Icon = config.icon
return (
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${config.color}`}>
<Icon className="h-3 w-3 mr-1" />
{label || status.charAt(0).toUpperCase() + status.slice(1)}
</span>
)
}
const ProgressBar = ({ percentage, color = 'blue' }) => {
const colorClasses = {
blue: 'bg-blue-600',
green: 'bg-green-600',
yellow: 'bg-yellow-600',
red: 'bg-red-600'
}
const barColor = percentage > 80 ? 'red' : percentage > 60 ? 'yellow' : 'green'
return (
<div className="w-full bg-gray-200 rounded-full h-2">
<div
className={`h-2 rounded-full transition-all duration-300 ${colorClasses[barColor]}`}
style={{ width: `${Math.min(percentage, 100)}%` }}
></div>
</div>
)
}
const ContainerCard = ({ name, metrics }) => (
<div className="bg-gray-50 rounded-lg p-4 border">
<h4 className="font-medium text-gray-900 mb-3 truncate" title={name}>
{name.replace('drone-detection-', '').replace('uamils-', '')}
</h4>
<div className="space-y-2 text-sm">
<div className="flex justify-between">
<span className="text-gray-500">CPU</span>
<span className="font-medium">{metrics.cpu}</span>
</div>
<div className="flex justify-between">
<span className="text-gray-500">Memory</span>
<span className="font-medium">{metrics.memory.percentage}</span>
</div>
<div className="flex justify-between">
<span className="text-gray-500">Network I/O</span>
<span className="font-medium text-xs">{metrics.network}</span>
</div>
<div className="flex justify-between">
<span className="text-gray-500">Disk I/O</span>
<span className="font-medium text-xs">{metrics.disk}</span>
</div>
</div>
</div>
)
const SSLCard = ({ domain, ssl }) => (
<div className="bg-gray-50 rounded-lg p-4 border">
<h4 className="font-medium text-gray-900 mb-2 truncate" title={domain}>
{domain}
</h4>
<div className="space-y-2">
<div className="flex justify-between items-center">
<span className="text-sm text-gray-500">Status</span>
<StatusIndicator status={ssl.status} />
</div>
{ssl.expiresAt && (
<>
<div className="flex justify-between text-sm">
<span className="text-gray-500">Expires</span>
<span className="font-medium">
{new Date(ssl.expiresAt).toLocaleDateString()}
</span>
</div>
{ssl.daysUntilExpiry !== undefined && (
<div className="flex justify-between text-sm">
<span className="text-gray-500">Days Left</span>
<span className={`font-medium ${ssl.daysUntilExpiry < 30 ? 'text-red-600' : 'text-green-600'}`}>
{ssl.daysUntilExpiry}
</span>
</div>
)}
{ssl.issuer && (
<div className="text-xs text-gray-400 truncate" title={ssl.issuer}>
Issuer: {ssl.issuer}
</div>
)}
</>
)}
{ssl.error && (
<div className="text-xs text-red-600">
{ssl.error}
</div>
)}
</div>
</div>
)
if (loading) {
return (
<div className="flex items-center justify-center h-64">
@@ -84,110 +174,144 @@ const System = () => {
)
}
if (!systemInfo) {
return (
<div className="text-center py-12">
<XCircleIcon className="mx-auto h-12 w-12 text-red-400" />
<h3 className="mt-2 text-sm font-medium text-gray-900">No system information available</h3>
<p className="mt-1 text-sm text-gray-500">Unable to load system metrics.</p>
<div className="mt-6">
<button
onClick={loadSystemInfo}
className="inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700"
>
Retry
</button>
</div>
</div>
)
}
return (
<div>
<div className="mb-8">
<h1 className="text-2xl font-bold text-gray-900">System</h1>
<p className="text-gray-600">Monitor system health and configuration</p>
<div className="mb-8 flex justify-between items-center">
<div>
<h1 className="text-2xl font-bold text-gray-900">System Monitor</h1>
<p className="text-gray-600">Real-time system health and configuration monitoring</p>
{lastUpdate && (
<p className="text-xs text-gray-400 mt-1">
Last updated: {lastUpdate.toLocaleTimeString()}
</p>
)}
</div>
<button
onClick={loadSystemInfo}
className="inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"
>
<CogIcon className="h-4 w-4 mr-2" />
Refresh
</button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-8">
<StatusCard title="Server Status" icon={ServerIcon}>
{/* Platform Overview */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
<StatusCard title="Platform Status" icon={ServerIcon}>
<div className="space-y-3">
<div className="flex justify-between">
<span className="text-sm text-gray-500">Version</span>
<span className="text-sm font-medium">{systemInfo.version}</span>
<span className="text-sm font-medium">{systemInfo.platform.version}</span>
</div>
<div className="flex justify-between">
<span className="text-sm text-gray-500">Environment</span>
<span className="text-sm font-medium capitalize">{systemInfo.environment}</span>
<span className="text-sm font-medium capitalize">{systemInfo.platform.environment}</span>
</div>
<div className="flex justify-between">
<span className="text-sm text-gray-500">Uptime</span>
<span className="text-sm font-medium">{systemInfo.uptime}</span>
<span className="text-sm font-medium">{systemInfo.platform.uptime}</span>
</div>
</div>
</StatusCard>
<StatusCard title="Database" icon={CircleStackIcon}>
<StatusCard title="System Resources" icon={CpuChipIcon}>
<div className="space-y-3">
<div className="flex justify-between">
<span className="text-sm text-gray-500">Status</span>
<StatusIndicator status={systemInfo.database.status} />
<div>
<div className="flex justify-between text-sm mb-1">
<span className="text-gray-500">CPU Usage</span>
<span className="font-medium">{systemInfo.system.cpu.usage}</span>
</div>
<ProgressBar percentage={systemInfo.system.cpu.percentage} />
</div>
<div className="flex justify-between">
<span className="text-sm text-gray-500">Version</span>
<span className="text-sm font-medium">{systemInfo.database.version}</span>
<div>
<div className="flex justify-between text-sm mb-1">
<span className="text-gray-500">Memory</span>
<span className="font-medium">{systemInfo.system.memory.used} / {systemInfo.system.memory.total}</span>
</div>
<ProgressBar percentage={systemInfo.system.memory.percentage} />
</div>
<div className="flex justify-between">
<span className="text-sm text-gray-500">Connections</span>
<span className="text-sm font-medium">
{systemInfo.database.connections}/{systemInfo.database.maxConnections}
</span>
<div className="flex justify-between text-sm">
<span className="text-gray-500">Disk</span>
<span className="font-medium text-xs">{systemInfo.system.disk}</span>
</div>
</div>
</StatusCard>
<StatusCard title="SSL Certificate" icon={ShieldCheckIcon}>
<StatusCard title="Statistics" icon={ChartBarIcon}>
<div className="space-y-3">
<div className="flex justify-between">
<span className="text-sm text-gray-500">Status</span>
<StatusIndicator status={systemInfo.ssl.status} />
<span className="text-sm text-gray-500">Tenants</span>
<span className="text-sm font-medium">{systemInfo.statistics.tenants}</span>
</div>
<div className="flex justify-between">
<span className="text-sm text-gray-500">Expires</span>
<span className="text-sm font-medium">
{new Date(systemInfo.ssl.expiresAt).toLocaleDateString()}
</span>
<span className="text-sm text-gray-500">Total Users</span>
<span className="text-sm font-medium">{systemInfo.statistics.total_users}</span>
</div>
<div className="flex justify-between">
<span className="text-sm text-gray-500">Access Level</span>
<span className="text-sm font-medium capitalize">{systemInfo.security.management_access_level}</span>
</div>
</div>
</StatusCard>
<StatusCard title="Backup Status" icon={ClockIcon}>
<div className="text-center">
<div className="text-sm font-medium text-gray-900 mb-2">
{systemInfo.security.last_backup !== 'Not configured'
? new Date(systemInfo.security.last_backup).toLocaleDateString()
: 'Not configured'
}
</div>
<button className="w-full bg-blue-600 text-white px-3 py-2 rounded-lg hover:bg-blue-700 transition-colors text-sm">
Run Backup
</button>
</div>
</StatusCard>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div className="bg-white rounded-lg shadow p-6">
<h3 className="text-lg font-medium text-gray-900 mb-4 flex items-center">
<CogIcon className="h-5 w-5 text-blue-600 mr-2" />
Memory Usage
</h3>
<div className="space-y-3">
<div className="flex justify-between text-sm">
<span className="text-gray-500">Used</span>
<span className="font-medium">{systemInfo.memory.used}</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-500">Total</span>
<span className="font-medium">{systemInfo.memory.total}</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2">
<div
className="bg-blue-600 h-2 rounded-full"
style={{ width: `${systemInfo.memory.percentage}%` }}
></div>
</div>
<div className="text-xs text-gray-500 text-center">
{systemInfo.memory.percentage}% used
</div>
{/* Container Metrics */}
<div className="mb-8">
<StatusCard title="Container Metrics" icon={ServerIcon}>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{Object.entries(systemInfo.containers).map(([name, metrics]) => (
<ContainerCard key={name} name={name} metrics={metrics} />
))}
</div>
</div>
</StatusCard>
</div>
<div className="bg-white rounded-lg shadow p-6">
<h3 className="text-lg font-medium text-gray-900 mb-4 flex items-center">
<ClockIcon className="h-5 w-5 text-blue-600 mr-2" />
Last Backup
</h3>
<div className="text-center">
<div className="text-2xl font-bold text-gray-900">
{new Date(systemInfo.lastBackup).toLocaleDateString()}
</div>
<div className="text-sm text-gray-500">
{new Date(systemInfo.lastBackup).toLocaleTimeString()}
</div>
<button className="mt-4 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors">
Run Backup Now
</button>
{/* SSL Certificates */}
<div className="mb-8">
<StatusCard
title="SSL Certificates"
icon={ShieldCheckIcon}
status={Object.values(systemInfo.ssl).some(ssl => ssl.status === 'critical') ? 'critical' :
Object.values(systemInfo.ssl).some(ssl => ssl.status === 'warning') ? 'warning' : 'success'}
>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{Object.entries(systemInfo.ssl).map(([domain, ssl]) => (
<SSLCard key={domain} domain={domain} ssl={ssl} />
))}
</div>
</div>
</StatusCard>
</div>
</div>
)