import React, { useState } from 'react'; import { Badge, Button, MaturityBadge, Modal, useToast } from '../../shared/ui'; import { ArrowDown, Play, Plus, CheckCircle2, Check, Clock, Terminal, Power, } from 'lucide-react'; interface WorkflowNode { id: string; type: 'trigger' | 'condition' | 'ai' | 'action'; title: string; description: string; badge: string; badgeVariant: 'green' | 'gold' | 'info' | 'neutral'; latencyMs: number; } interface TestLogStep { stepNumber: number; nodeTitle: string; status: 'pending' | 'running' | 'success' | 'failed'; output: string; latencyMs: number; } const INITIAL_NODES: WorkflowNode[] = [ { id: 'n1', type: 'trigger', title: 'Триггер: Новое входящее сообщение в Telegram', description: 'Срабатывает мгновенно при обращении гостя в бота заведения', badge: 'Событие', badgeVariant: 'gold', latencyMs: 14, }, { id: 'n2', type: 'condition', title: 'Условие: Поиск клиента в базе CRM платформы', description: 'Проверка номера телефона и истории заказов: клиент найден в базе', badge: 'CRM Match', badgeVariant: 'neutral', latencyMs: 42, }, { id: 'n3', type: 'ai', title: '✦ Krona AI: Определение намерения гостя (Intent Analysis)', description: 'Классификация сообщения: запрос бронирования столика (уверенность 98%)', badge: 'ИИ-анализ', badgeVariant: 'gold', latencyMs: 175, }, { id: 'n4', type: 'action', title: 'Действие: Создание сделки и назначение менеджера', description: 'Открытие карточки сделки в воронке со статусом «Бронирование стола»', badge: 'CRM Сделка', badgeVariant: 'green', latencyMs: 65, }, { id: 'n5', type: 'action', title: 'Действие: Отправка подтверждения гостю в чат', description: 'Формирование персонализированного ответа с подтверждением даты и времени', badge: 'Telegram Reply', badgeVariant: 'info', latencyMs: 88, }, ]; export const AutomationModule: React.FC = () => { const { showToast } = useToast(); const [nodes, setNodes] = useState(INITIAL_NODES); const [isWorkflowActive, setIsWorkflowActive] = useState(true); // Test Run execution state const [isRunningTest, setIsRunningTest] = useState(false); const [testLogs, setTestLogs] = useState([]); const [testComplete, setTestComplete] = useState(false); // New Node Modal const [isNewNodeModalOpen, setIsNewNodeModalOpen] = useState(false); const [nodeType, setNodeType] = useState<'trigger' | 'condition' | 'ai' | 'action'>('action'); const [nodeTitle, setNodeTitle] = useState(''); const [nodeDesc, setNodeDesc] = useState(''); const handleRunTest = () => { setIsRunningTest(true); setTestComplete(false); setTestLogs([]); const logSteps: TestLogStep[] = [ { stepNumber: 1, nodeTitle: nodes[0].title, status: 'running', output: 'Получен вебхук Telegram: "Добрый вечер, хотим столик на четверых на 19:30"', latencyMs: 14 }, ]; setTestLogs([...logSteps]); setTimeout(() => { logSteps[0].status = 'success'; logSteps.push({ stepNumber: 2, nodeTitle: nodes[1]?.title || 'Поиск клиента', status: 'running', output: 'Поиск по номеру +7 (913) 482-19-02: Найден контакт «Анна Воронина» (VIP, 14 заказов)', latencyMs: 42, }); setTestLogs([...logSteps]); }, 400); setTimeout(() => { logSteps[1].status = 'success'; logSteps.push({ stepNumber: 3, nodeTitle: nodes[2]?.title || 'AI Анализ', status: 'running', output: 'Модель Krona NLP v1.8: Класс = table_booking, Персоны = 4, Время = 19:30, Confidence = 98.4%', latencyMs: 175, }); setTestLogs([...logSteps]); }, 900); setTimeout(() => { logSteps[2].status = 'success'; logSteps.push({ stepNumber: 4, nodeTitle: nodes[3]?.title || 'Создание сделки', status: 'running', output: 'Сделка #DL-9428 создана в воронке «Бронирование». Назначен менеджер: Алина Соколова', latencyMs: 65, }); setTestLogs([...logSteps]); }, 1400); setTimeout(() => { logSteps[3].status = 'success'; logSteps.push({ stepNumber: 5, nodeTitle: nodes[4]?.title || 'Отправка ответа', status: 'success', output: 'Сообщение доставлено пользователю: "Анна, здравствуйте! Забронировали Стол 5 на 19:30."', latencyMs: 88, }); setTestLogs([...logSteps]); setIsRunningTest(false); setTestComplete(true); showToast({ title: 'Тестовый запуск успешен!', message: 'Все 5 узлов цепочки выполнены без ошибок за 384 ms', type: 'success', }); }, 1900); }; const handleAddNode = (e: React.FormEvent) => { e.preventDefault(); if (!nodeTitle.trim()) return; const badgeVariants: Record = { trigger: 'gold', condition: 'neutral', ai: 'gold', action: 'green', }; const newNode: WorkflowNode = { id: `n-${Date.now()}`, type: nodeType, title: nodeTitle.trim(), description: nodeDesc.trim() || 'Пользовательский шаг автоматизации', badge: nodeType.toUpperCase(), badgeVariant: badgeVariants[nodeType], latencyMs: Math.floor(20 + Math.random() * 80), }; setNodes((prev) => [...prev, newNode]); setIsNewNodeModalOpen(false); setNodeTitle(''); setNodeDesc(''); showToast({ title: 'Узел добавлен в цепочку', message: `Блок «${newNode.title}» готов к выполнению`, type: 'success', }); }; const totalLatency = nodes.reduce((sum, n) => sum + n.latencyMs, 0); return (
{/* Header with MaturityBadge */}

Автоматизация & Visual Workflow Engine

Визуальный конструктор бизнес-процессов: триггеры, условия, AI-агенты и автоматические действия

{/* Left: Visual Workflow Chain */}

Сценарий: «Автоматическая обработка брони стола из Telegram»

Всего шагов: {nodes.length} • Среднее время сквозного выполнения: ~{totalLatency} ms
{isWorkflowActive ? 'Работает в фоне' : 'На паузе'}
{/* Flow Nodes List */}
{nodes.map((node, i) => (
{node.title}

{node.description}

Ожидаемая задержка: ~{node.latencyMs} ms
{node.badge}
{i < nodes.length - 1 && (
)}
))}
{/* Right: Test Run Execution Console */}
Консоль тестового прогона (Test Run)

Симуляция сквозного прохождения входящего события по всем шагам сценария с замером задержки каждого узла:

{/* Execution logs output */}
{testLogs.length === 0 ? (
Нажмите «Тестовый запуск» для симуляции выполнения сценария
) : ( testLogs.map((step) => (
[ШАГ {step.stepNumber}] {step.nodeTitle} {step.latencyMs} ms
{step.output}
{step.status === 'success' && ( УСПЕШНО )} {step.status === 'running' && ( ВЫПОЛНЕНИЕ... )}
)) )} {testComplete && (
✓ ВСЕ ШАГИ ВЫПОЛНЕНЫ УСПЕШНО (ИТОГО: 384 ms)
)}
Логи тестового запуска записываются в журнал аудита безопасности.
{/* Modal: New Node */} {isNewNodeModalOpen && ( setIsNewNodeModalOpen(false)} title="Добавить узел автоматизации" subtitle="Выбор типа операции в цепочке" maxWidth="sm" footer={
} >
setNodeTitle(e.target.value)} placeholder="Например: Отправить уведомление в Telegram администратору" className="w-full p-2 bg-krona-workspace border border-krona-border rounded-lg text-krona-primary focus:outline-none focus:border-krona-green" />