Files
microdao-daarion/apps/web/src/components/ui/AgentPresenceBadge.tsx
Apple fcdac0f33c feat: implement Agent Presence Indicators (MVP)
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.
2025-11-30 09:41:57 -08:00

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;
}