Add configurable scheduling, UI health/task indicators, and auto-load map with default filters
This commit is contained in:
parent
1c8c3e4657
commit
c7ac448f15
18 changed files with 2287 additions and 656 deletions
83
crawler/frontend/src/components/HealthIndicator.tsx
Normal file
83
crawler/frontend/src/components/HealthIndicator.tsx
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './ui/tooltip';
|
||||
import { checkBackendHealth, type HealthStatus, type HealthCheckResult } from '@/services';
|
||||
import { Circle, Loader2 } from 'lucide-react';
|
||||
|
||||
interface HealthIndicatorProps {
|
||||
/** How often to check health in milliseconds (default: 30000 = 30s) */
|
||||
interval?: number;
|
||||
}
|
||||
|
||||
export function HealthIndicator({ interval = 30000 }: HealthIndicatorProps) {
|
||||
const [health, setHealth] = useState<HealthCheckResult>({ status: 'checking' });
|
||||
|
||||
useEffect(() => {
|
||||
// Initial check
|
||||
checkBackendHealth().then(setHealth);
|
||||
|
||||
// Periodic checks
|
||||
const intervalId = setInterval(() => {
|
||||
checkBackendHealth().then(setHealth);
|
||||
}, interval);
|
||||
|
||||
return () => clearInterval(intervalId);
|
||||
}, [interval]);
|
||||
|
||||
const getStatusColor = (status: HealthStatus) => {
|
||||
switch (status) {
|
||||
case 'healthy':
|
||||
return 'text-green-500';
|
||||
case 'unhealthy':
|
||||
return 'text-red-500';
|
||||
case 'checking':
|
||||
return 'text-muted-foreground';
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusLabel = (status: HealthStatus) => {
|
||||
switch (status) {
|
||||
case 'healthy':
|
||||
return 'Connected';
|
||||
case 'unhealthy':
|
||||
return 'Disconnected';
|
||||
case 'checking':
|
||||
return 'Checking...';
|
||||
}
|
||||
};
|
||||
|
||||
const getTooltipContent = () => {
|
||||
if (health.status === 'checking') {
|
||||
return 'Checking backend connection...';
|
||||
}
|
||||
|
||||
if (health.status === 'healthy') {
|
||||
return `Backend connected (${health.latencyMs}ms)`;
|
||||
}
|
||||
|
||||
return `Backend unavailable: ${health.error || 'Unknown error'}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<div className="flex items-center gap-1.5 cursor-default">
|
||||
{health.status === 'checking' ? (
|
||||
<Loader2 className="h-3 w-3 animate-spin text-muted-foreground" />
|
||||
) : (
|
||||
<Circle
|
||||
className={`h-2.5 w-2.5 fill-current ${getStatusColor(health.status)}`}
|
||||
/>
|
||||
)}
|
||||
<span className={`text-xs ${getStatusColor(health.status)} hidden sm:inline`}>
|
||||
{getStatusLabel(health.status)}
|
||||
</span>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">
|
||||
<p>{getTooltipContent()}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue