Backend: - Add /api/v1/agents/presence endpoint - Integrate with matrix-presence-aggregator - Add DAGI router health checks Frontend: - Create useAgentPresence hook - Create AgentPresenceBadge component - Integrate into /agents list page - Integrate into /agents/:agentId cabinet Shows real-time online/offline status for all agents.
101 lines
2.3 KiB
TypeScript
101 lines
2.3 KiB
TypeScript
'use client';
|
|
|
|
import { useAgentPresence } from '@/hooks/useAgentPresence';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
interface AgentPresenceBadgeProps {
|
|
agentId: string;
|
|
size?: 'sm' | 'md' | 'lg';
|
|
showLabel?: boolean;
|
|
showTooltip?: boolean;
|
|
className?: string;
|
|
}
|
|
|
|
/**
|
|
* Presence Badge для агентів.
|
|
*
|
|
* Показує статус: online (зелений), away/unavailable (жовтий), offline (сірий).
|
|
* Підтримує tooltip з деталями.
|
|
*/
|
|
export function AgentPresenceBadge({
|
|
agentId,
|
|
size = 'sm',
|
|
showLabel = false,
|
|
showTooltip = true,
|
|
className
|
|
}: AgentPresenceBadgeProps) {
|
|
const { getPresence, getPresenceStatus, loading } = useAgentPresence();
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className={cn('animate-pulse', className)}>
|
|
<div className={cn(
|
|
'rounded-full bg-gray-400',
|
|
size === 'sm' && 'w-2 h-2',
|
|
size === 'md' && 'w-3 h-3',
|
|
size === 'lg' && 'w-4 h-4'
|
|
)} />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const presence = getPresence(agentId);
|
|
const status = getPresenceStatus(agentId);
|
|
|
|
const getStatusInfo = () => {
|
|
switch (status) {
|
|
case 'online':
|
|
return {
|
|
color: 'bg-emerald-500',
|
|
label: 'Online',
|
|
description: 'Агент активний'
|
|
};
|
|
case 'away':
|
|
return {
|
|
color: 'bg-amber-500',
|
|
label: 'Away',
|
|
description: 'Агент неактивний'
|
|
};
|
|
default:
|
|
return {
|
|
color: 'bg-gray-500',
|
|
label: 'Offline',
|
|
description: 'Агент офлайн'
|
|
};
|
|
}
|
|
};
|
|
|
|
const statusInfo = getStatusInfo();
|
|
const sizeClasses = {
|
|
sm: 'w-2 h-2',
|
|
md: 'w-3 h-3',
|
|
lg: 'w-4 h-4'
|
|
};
|
|
|
|
const badge = (
|
|
<div
|
|
className={cn('flex items-center gap-1.5', className)}
|
|
title={presence ? `${presence.display_name}: ${statusInfo.description}` : undefined}
|
|
>
|
|
<div className={cn(
|
|
'rounded-full border border-white/20',
|
|
sizeClasses[size],
|
|
statusInfo.color
|
|
)} />
|
|
|
|
{showLabel && (
|
|
<span className={cn(
|
|
'text-white/70',
|
|
size === 'sm' && 'text-xs',
|
|
size === 'md' && 'text-sm',
|
|
size === 'lg' && 'text-base'
|
|
)}>
|
|
{statusInfo.label}
|
|
</span>
|
|
)}
|
|
</div>
|
|
);
|
|
|
|
return badge;
|
|
}
|