Spaces:
Running
Running
File size: 4,521 Bytes
c0a9bce |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
import { useState, useEffect } from 'react';
import type { ServiceStatus } from './types';
import { ProviderStatusCheckerFactory } from './provider-factory';
export default function ServiceStatusTab() {
const [serviceStatuses, setServiceStatuses] = useState<ServiceStatus[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const checkAllProviders = async () => {
try {
setLoading(true);
setError(null);
const providers = ProviderStatusCheckerFactory.getProviderNames();
const statuses: ServiceStatus[] = [];
for (const provider of providers) {
try {
const checker = ProviderStatusCheckerFactory.getChecker(provider);
const result = await checker.checkStatus();
statuses.push({
provider,
...result,
lastChecked: new Date().toISOString(),
});
} catch (err) {
console.error(`Error checking ${provider} status:`, err);
statuses.push({
provider,
status: 'degraded',
message: 'Unable to check service status',
incidents: ['Error checking service status'],
lastChecked: new Date().toISOString(),
});
}
}
setServiceStatuses(statuses);
} catch (err) {
console.error('Error checking provider statuses:', err);
setError('Failed to check service statuses');
} finally {
setLoading(false);
}
};
checkAllProviders();
// Set up periodic checks every 5 minutes
const interval = setInterval(checkAllProviders, 5 * 60 * 1000);
return () => clearInterval(interval);
}, []);
const getStatusColor = (status: ServiceStatus['status']) => {
switch (status) {
case 'operational':
return 'text-green-500 dark:text-green-400';
case 'degraded':
return 'text-yellow-500 dark:text-yellow-400';
case 'down':
return 'text-red-500 dark:text-red-400';
default:
return 'text-gray-500 dark:text-gray-400';
}
};
const getStatusIcon = (status: ServiceStatus['status']) => {
switch (status) {
case 'operational':
return 'i-ph:check-circle';
case 'degraded':
return 'i-ph:warning';
case 'down':
return 'i-ph:x-circle';
default:
return 'i-ph:question';
}
};
if (loading) {
return (
<div className="flex items-center justify-center h-full">
<div className="animate-spin i-ph:circle-notch w-8 h-8 text-purple-500" />
</div>
);
}
if (error) {
return (
<div className="flex flex-col items-center justify-center h-full text-red-500 dark:text-red-400">
<div className="i-ph:warning w-8 h-8 mb-2" />
<p>{error}</p>
</div>
);
}
return (
<div className="space-y-6">
<div className="grid grid-cols-1 gap-4">
{serviceStatuses.map((service) => (
<div
key={service.provider}
className="p-4 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700"
>
<div className="flex items-center justify-between mb-2">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">{service.provider}</h3>
<div className={`flex items-center ${getStatusColor(service.status)}`}>
<div className={`${getStatusIcon(service.status)} w-5 h-5 mr-2`} />
<span className="capitalize">{service.status}</span>
</div>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-2">{service.message}</p>
{service.incidents && service.incidents.length > 0 && (
<div className="mt-2">
<h4 className="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-1">Recent Incidents:</h4>
<ul className="text-sm text-gray-600 dark:text-gray-400 space-y-1">
{service.incidents.map((incident, index) => (
<li key={index}>{incident}</li>
))}
</ul>
</div>
)}
<div className="mt-2 text-xs text-gray-500 dark:text-gray-400">
Last checked: {new Date(service.lastChecked).toLocaleString()}
</div>
</div>
))}
</div>
</div>
);
}
|