/** * AutomationCenter — Phase 5: Automation Fabric * * Visão unificada de todas as automações: Central + XOS. * Rota: /automations-center */ import { useState } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { BrowserFrame } from "@/components/Browser/BrowserFrame"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { Switch } from "@/components/ui/switch"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Zap, Search, Play, Loader2, CheckCircle, XCircle, Clock, Webhook, Bot, Calendar, Activity, Filter } from "lucide-react"; import { useToast } from "@/hooks/use-toast"; interface UnifiedAutomation { id: string; sourceId: number; source: "central" | "xos"; name: string; description: string | null; triggerType: string; isActive: boolean; executionCount: number; lastExecutedAt: string | null; createdAt: string; } const TRIGGER_ICONS: Record = { schedule: , webhook: , agent: , event: , contact_created: , deal_stage_changed: , form_submitted: , }; const TRIGGER_LABEL: Record = { schedule: "Agendada", webhook: "Webhook", manual: "Manual", event: "Evento", agent: "Agente", contact_created: "Novo Contato", deal_stage_changed: "Mudança de Etapa", form_submitted: "Formulário", }; export default function AutomationCenter() { const [search, setSearch] = useState(""); const [filterSource, setFilterSource] = useState<"all" | "central" | "xos">("all"); const [filterStatus, setFilterStatus] = useState<"all" | "active" | "inactive">("all"); const { toast } = useToast(); const qc = useQueryClient(); const { data, isLoading } = useQuery<{ automations: UnifiedAutomation[]; total: number }>({ queryKey: ["/api/automation-fabric/list"], refetchInterval: 30_000, }); const runMutation = useMutation({ mutationFn: async (id: string) => { const res = await fetch(`/api/automation-fabric/${encodeURIComponent(id)}/run`, { method: "POST" }); if (!res.ok) throw new Error(); return res.json(); }, onSuccess: (_, id) => { toast({ title: "Automação executada" }); qc.invalidateQueries({ queryKey: ["/api/automation-fabric/list"] }); }, onError: () => toast({ title: "Erro ao executar", variant: "destructive" }), }); const toggleMutation = useMutation({ mutationFn: async ({ id, isActive }: { id: string; isActive: boolean }) => { const res = await fetch(`/api/automation-fabric/${encodeURIComponent(id)}/toggle`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ isActive }), }); if (!res.ok) throw new Error(); return res.json(); }, onSuccess: () => qc.invalidateQueries({ queryKey: ["/api/automation-fabric/list"] }), onError: () => toast({ title: "Erro ao atualizar status", variant: "destructive" }), }); const automations = data?.automations ?? []; const filtered = automations.filter((a) => { if (filterSource !== "all" && a.source !== filterSource) return false; if (filterStatus === "active" && !a.isActive) return false; if (filterStatus === "inactive" && a.isActive) return false; if (search) { const q = search.toLowerCase(); return ( a.name.toLowerCase().includes(q) || (a.description ?? "").toLowerCase().includes(q) || a.triggerType.toLowerCase().includes(q) ); } return true; }); const activeCount = automations.filter((a) => a.isActive).length; const centralCount = automations.filter((a) => a.source === "central").length; const xosCount = automations.filter((a) => a.source === "xos").length; return (
{/* Header */}

Automation Center

{automations.length} automações · {activeCount} ativas · Central ({centralCount}) + XOS ({xosCount})

{/* Filters */}
setSearch(e.target.value)} className="pl-8 h-8 text-sm bg-white/5 border-white/10" />
{/* Source filter */}
{(["all", "central", "xos"] as const).map((s) => ( ))}
{/* Status filter */}
{(["all", "active", "inactive"] as const).map((s) => ( ))}
{/* List */} {isLoading && (
)} {!isLoading && filtered.length === 0 && (

Nenhuma automação encontrada

{search &&

Tente outro filtro ou busca

}
)}
{filtered.map((a) => { const isRunning = runMutation.isPending && runMutation.variables === a.id; const isToggling = toggleMutation.isPending && toggleMutation.variables?.id === a.id; const triggerIcon = TRIGGER_ICONS[a.triggerType] ?? ; const triggerLabel = TRIGGER_LABEL[a.triggerType] ?? a.triggerType; const lastRun = a.lastExecutedAt ? new Date(a.lastExecutedAt).toLocaleDateString("pt-BR") : null; return (
{/* Icon */}
{triggerIcon}
{/* Info */}
{a.name} {a.source === "central" ? "Central" : "XOS"}
{triggerIcon} {triggerLabel} {a.executionCount > 0 && ( {a.executionCount}x )} {lastRun && ( {lastRun} )}
{/* Actions */}
toggleMutation.mutate({ id: a.id, isActive: v })} className="scale-75" />
); })}
); }