godcrm/components/AIChatPanel/hooks/usePanelContent/AgentsPanelContent.tsx
GOD CRM Release f89e074dd1
Some checks failed
CI / Lint / Typecheck / Test / Build (push) Has been cancelled
CI / PostgreSQL Integration Tests (push) Has been cancelled
GOD CRM — public scrubbed snapshot
Governed substrate for autonomous agents: scoped identity (passports),
audited actions, MCP workspace. Infra IPs and secrets redacted for public release.
2026-08-10 04:01:45 +03:00

101 lines
7.6 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/** AgentsPanelContent — ADR-119 extracted from usePanelContent.tsx */
import React from 'react';
import { X, Search, Star, Loader2, Brain, Bot, Plus, MessageSquare } from 'lucide-react';
import { cn } from '@/shared/utils/cn';
import type { PanelContentDeps } from './PanelContentTypes';
export function AgentsPanelContent(d: PanelContentDeps) {
return (
<div className="flex flex-col h-full">
<div className="px-2 py-1.5 border-b border-[var(--border-secondary)] flex items-center gap-1.5">
<div className="flex-1 relative">
<Search className="absolute left-2 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-[var(--text-tertiary)]" />
<input type="text" value={d.agentsSearch}
onChange={(e) => { d.setAgentsSearch(e.target.value); if (!e.target.value) d.setVectorSearchResults(null); }}
placeholder="Поиск агентов..."
className="w-full pl-7 pr-2 py-1.5 text-xs rounded-lg bg-[var(--bg-tertiary)] border border-[var(--border-secondary)] text-[var(--text-primary)] placeholder:text-[var(--text-tertiary)] focus:outline-none focus:ring-1 focus:ring-[var(--color-primary-500)]/50" />
{d.agentsSearch && (
<button onClick={() => { d.setAgentsSearch(''); d.setVectorSearchResults(null); }}
className="absolute right-2 top-1/2 -translate-y-1/2 text-[var(--text-tertiary)] hover:text-[var(--text-primary)]">
<X className="w-3 h-3" />
</button>
)}
</div>
<button onClick={() => d.setShowFavoriteAgents(!d.showFavoriteAgents)}
className={cn("p-1.5 rounded-lg border transition-colors",
d.showFavoriteAgents ? "bg-yellow-500/20 text-yellow-500 border-yellow-500/30" : "text-[var(--text-tertiary)] border-[var(--border-secondary)] hover:bg-[var(--bg-tertiary)] hover:text-[var(--text-primary)]"
)} title={d.showFavoriteAgents ? "Показать всех" : "Только избранные"}>
<Star className={cn("w-3.5 h-3.5", d.showFavoriteAgents && "fill-current")} />
</button>
<button onClick={d.handleVectorSearch} disabled={d.isVectorSearching || !d.agentsSearch}
className={cn("p-1.5 rounded-lg border transition-colors",
d.vectorSearchResults ? "bg-green-500/20 text-green-400 border-green-500/30" : "text-[var(--text-tertiary)] border-[var(--border-secondary)] hover:bg-purple-500/10 hover:text-purple-400 hover:border-purple-500/30",
(!d.agentsSearch || d.isVectorSearching) && "opacity-50 cursor-not-allowed"
)} title={d.vectorSearchResults ? "AI поиск активен" : "Семантический поиск"}>
{d.isVectorSearching ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <Brain className="w-3.5 h-3.5" />}
</button>
</div>
<div className="flex-1 overflow-y-auto">
{d.filteredAgents.length === 0 ? (
d.agentsSearch ? (
<div className="py-8 text-center text-sm text-[var(--text-tertiary)]">Не найдено</div>
) : d.isLoadingAgents ? (
<div className="py-8 flex flex-col items-center gap-3">
<Loader2 className="w-6 h-6 animate-spin text-[var(--color-primary-500)]" />
<span className="text-sm text-[var(--text-tertiary)]">Загрузка агентов...</span>
</div>
) : (
<div className="p-6 text-center">
<div className="w-14 h-14 rounded-full bg-gradient-to-br from-purple-500/20 to-primary-500/20 flex items-center justify-center mb-4 mx-auto">
<Bot className="w-7 h-7 text-[var(--color-primary-500)]" />
</div>
<h3 className="font-medium text-[var(--text-primary)] mb-2">AI агенты не настроены</h3>
<p className="text-sm text-[var(--text-tertiary)] mb-4">Создайте AI таблицы в System Data для работы с агентами</p>
<button onClick={() => d.createTablesMutation.mutate()} disabled={d.createTablesMutation.isPending || !d.currentSpace?.id}
className="px-4 py-2 bg-[var(--color-primary-500)] text-white rounded-lg hover:bg-[var(--color-primary-600)] disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center gap-2 font-medium mx-auto">
{d.createTablesMutation.isPending ? (<><Loader2 className="w-4 h-4 animate-spin" />Создание...</>) : (<><Plus className="w-4 h-4" />Создать AI таблицы</>)}
</button>
{d.createTablesMutation.isError && <p className="text-sm text-red-500 mt-2">Ошибка создания таблиц</p>}
</div>
)
) : (
d.filteredAgents.map(agent => {
const isFavorite = d.favoriteAgents.includes(agent.id);
return (
<div key={agent.id} className="border-b border-[var(--border-secondary)] last:border-b-0">
<div className={cn("flex items-center gap-2 px-3 py-2 transition-colors group",
d.currentAgent?.id === agent.id ? "bg-[var(--color-primary-500)]/10" : "hover:bg-[var(--bg-tertiary)]")}>
<button onClick={(e) => { e.stopPropagation(); d.setFavoriteAgents(prev => isFavorite ? prev.filter(id => id !== agent.id) : [...prev, agent.id]); }}
className={cn("p-1 rounded border transition-colors",
isFavorite ? "text-yellow-500 border-yellow-500/30 bg-yellow-500/10" : "text-[var(--text-tertiary)] border-[var(--border-secondary)] hover:text-yellow-500 hover:border-yellow-500/30"
)} title={isFavorite ? "Убрать из избранного" : "В избранное"}>
<Star className={cn("w-3.5 h-3.5", isFavorite && "fill-current")} />
</button>
<button onClick={() => d.handleAgentSelect(agent)} className="flex items-center gap-2 flex-1 min-w-0 text-left">
<div className={cn("w-8 h-8 rounded-full flex items-center justify-center text-base flex-shrink-0",
d.currentAgent?.id === agent.id ? "bg-[var(--color-primary-500)]/20" : "bg-[var(--bg-tertiary)]")}>
{agent.icon || '\uD83E\uDD16'}
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-1.5">
<span className="text-sm font-medium text-[var(--text-primary)] truncate">{agent.name}</span>
{d.currentAgent?.id === agent.id && <span className="text-[9px] px-1 py-0.5 rounded bg-[var(--color-primary-500)]/30 text-[var(--color-primary-400)] flex-shrink-0">активен</span>}
</div>
{agent.description && <p className="text-[10px] text-[var(--text-tertiary)] truncate">{agent.description}</p>}
</div>
</button>
<div className="flex items-center gap-1">
<button onClick={(e) => { e.stopPropagation(); d.handleAgentSelect(agent); d.clearMessages(); d.setActivePanel('none'); }}
className="p-1.5 rounded border border-[var(--border-secondary)] text-[var(--text-tertiary)] hover:text-[var(--color-primary-500)] hover:border-[var(--color-primary-500)]/30 hover:bg-[var(--color-primary-500)]/10 transition-colors" title="Новый чат">
<MessageSquare className="w-3.5 h-3.5" />
</button>
</div>
</div>
</div>
);
})
)}
</div>
</div>
);
}