'use client'; import { useState, useEffect } from 'react'; import Link from 'next/link'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Switch } from '@/components/ui/switch'; import { ArrowLeft, Plus, Workflow, Play, Pause, Trash2, Settings, History, Zap, GitBranch, } from 'lucide-react'; interface Pipeline { id: number; name: string; description: string | null; is_active: boolean; trigger_source: string; trigger_conditions: any[]; sort_order: number; step_count: number; created_at: string; updated_at: string; } const SOURCE_LABELS: Record = { datto_rmm: { label: 'Datto RMM', color: 'bg-blue-100 text-blue-800' }, autotask: { label: 'Autotask', color: 'bg-green-100 text-green-800' }, veeam: { label: 'Veeam', color: 'bg-purple-100 text-purple-800' }, manual: { label: 'Manual', color: 'bg-gray-100 text-gray-800' }, }; export default function PipelinesPage() { const [pipelines, setPipelines] = useState([]); const [isLoading, setIsLoading] = useState(true); const [showCreate, setShowCreate] = useState(false); const [newPipeline, setNewPipeline] = useState({ name: '', description: '', trigger_source: 'datto_rmm' }); useEffect(() => { loadPipelines(); }, []); const loadPipelines = async () => { setIsLoading(true); try { const res = await fetch('/api/pipelines'); if (res.ok) { const data = await res.json(); setPipelines(data.data || []); } } catch (err) { console.error('Failed to load pipelines:', err); } finally { setIsLoading(false); } }; const togglePipeline = async (id: number, active: boolean) => { try { await fetch(`/api/pipelines/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ is_active: active }), }); setPipelines(prev => prev.map(p => p.id === id ? { ...p, is_active: active } : p)); } catch (err) { console.error('Failed to toggle pipeline:', err); } }; const deletePipeline = async (id: number) => { if (!confirm('Delete this pipeline and all its steps?')) return; try { await fetch(`/api/pipelines/${id}`, { method: 'DELETE' }); setPipelines(prev => prev.filter(p => p.id !== id)); } catch (err) { console.error('Failed to delete pipeline:', err); } }; const createPipeline = async () => { if (!newPipeline.name) return; try { const res = await fetch('/api/pipelines', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...newPipeline, is_active: false }), }); if (res.ok) { setShowCreate(false); setNewPipeline({ name: '', description: '', trigger_source: 'datto_rmm' }); loadPipelines(); } } catch (err) { console.error('Failed to create pipeline:', err); } }; return (

Webhook Pipelines

Automate actions triggered by incoming webhooks

{showCreate && ( Create Pipeline
setNewPipeline(p => ({ ...p, name: e.target.value }))} />
setNewPipeline(p => ({ ...p, description: e.target.value }))} />
)} {isLoading ? (
Loading pipelines...
) : pipelines.length === 0 ? (

No pipelines yet. Create one to get started.

) : (
{pipelines.map(pipeline => { const source = SOURCE_LABELS[pipeline.trigger_source] || { label: pipeline.trigger_source, color: 'bg-gray-100 text-gray-800' }; return (
togglePipeline(pipeline.id, checked)} />
{pipeline.name} {source.label} {pipeline.step_count} steps {pipeline.trigger_conditions?.length > 0 && ( {pipeline.trigger_conditions.length} condition{pipeline.trigger_conditions.length > 1 ? 's' : ''} )}
{pipeline.description && (

{pipeline.description}

)}
); })}
)}
); }