Fixed and changes
This commit is contained in:
@@ -8,15 +8,22 @@ interface ServiceStatus {
|
||||
url: string;
|
||||
status: 'up' | 'down';
|
||||
latency: number;
|
||||
uptime24h?: number;
|
||||
uptime7d?: number;
|
||||
}
|
||||
|
||||
// We'd ideally fetch stats from API, but for now we calculate from live data or mock
|
||||
// To do this properly, we need an API endpoint returning stats.
|
||||
// Let's update `api/status` to also return stats or create `api/status/stats`.
|
||||
// For this step, I'll update the visual to SHOW where stats would be,
|
||||
// and we'll implement the backend stats aggregation in the next step.
|
||||
|
||||
export function UptimeCard() {
|
||||
const [services, setServices] = useState<ServiceStatus[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(false);
|
||||
|
||||
const fetchStatus = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await fetch('/api/status');
|
||||
if (!res.ok) throw new Error('Failed to fetch');
|
||||
@@ -33,15 +40,10 @@ export function UptimeCard() {
|
||||
|
||||
useEffect(() => {
|
||||
fetchStatus();
|
||||
// Poll every 30 seconds
|
||||
const interval = setInterval(fetchStatus, 30000);
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
// Calculate overall health
|
||||
const upCount = services.filter(s => s.status === 'up').length;
|
||||
const healthPercentage = services.length > 0 ? Math.round((upCount / services.length) * 100) : 0;
|
||||
|
||||
return (
|
||||
<div className="col-span-1 md:col-span-2 lg:col-span-2 row-span-1 bg-neutral-900 border border-neutral-800 rounded-xl p-6 flex flex-col justify-between hover:border-neutral-700 transition-colors">
|
||||
<div className="flex justify-between items-start">
|
||||
@@ -50,11 +52,6 @@ export function UptimeCard() {
|
||||
<span className="text-sm font-medium">Uptime Monitor</span>
|
||||
{loading && <RefreshCcw size={12} className="animate-spin ml-2 opacity-50" />}
|
||||
</div>
|
||||
{!loading && !error && (
|
||||
<span className={`text-xs px-2 py-1 rounded-full font-mono ${healthPercentage === 100 ? 'bg-emerald-500/10 text-emerald-500' : 'bg-red-500/10 text-red-500'}`}>
|
||||
{healthPercentage}%
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{error ? (
|
||||
@@ -63,26 +60,30 @@ export function UptimeCard() {
|
||||
<span className="text-xs">Failed to load status</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-3 mt-4">
|
||||
{services.length === 0 && loading ? (
|
||||
// Skeleton loader
|
||||
[1, 2, 3].map(i => (
|
||||
<div key={i} className="flex items-center justify-between animate-pulse">
|
||||
<div className="h-4 w-20 bg-neutral-800 rounded"></div>
|
||||
<div className="h-2 w-2 bg-neutral-800 rounded-full"></div>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
services.map((service) => (
|
||||
<div key={service.name} className="flex items-center justify-between group">
|
||||
<div className="space-y-4 mt-4">
|
||||
{services.map((service) => (
|
||||
<div key={service.name} className="flex flex-col gap-1">
|
||||
<div className="flex items-center justify-between group">
|
||||
<span className="text-sm text-neutral-300 font-medium group-hover:text-white transition-colors">{service.name}</span>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs text-neutral-500 font-mono">{service.status === 'up' ? `${service.latency}ms` : 'DOWN'}</span>
|
||||
<div className={`w-2 h-2 rounded-full shadow-[0_0_8px_rgba(0,0,0,0.4)] ${service.status === 'up' ? 'bg-emerald-500 shadow-emerald-500/40' : 'bg-red-500 shadow-red-500/40'}`} />
|
||||
<span className={`text-xs px-1.5 py-0.5 rounded ${service.status === 'up' ? 'bg-emerald-500/10 text-emerald-500' : 'bg-red-500/10 text-red-500'}`}>
|
||||
{service.status === 'up' ? 'UP' : 'DOWN'}
|
||||
</span>
|
||||
<span className="text-xs text-neutral-500 font-mono w-10 text-right">{service.latency}ms</span>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
{/* Mini bars visualization for history - Mocked visual for now until API is ready */}
|
||||
<div className="flex gap-[2px] h-1.5 opacity-50">
|
||||
{[...Array(20)].map((_, i) => (
|
||||
<div key={i} className={`flex-1 rounded-full ${Math.random() > 0.95 ? 'bg-red-500' : 'bg-emerald-500'}`} />
|
||||
))}
|
||||
</div>
|
||||
<div className="flex justify-between text-[10px] text-neutral-600 font-mono">
|
||||
<span>24h: {service.uptime24h ?? 100}%</span>
|
||||
<span>7d: {service.uptime7d ?? 100}%</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user