"use client"; import { useEffect, useState } from "react"; import Link from "next/link"; import { Plus, RefreshCw, Trash2, Activity } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { api, type FlowSummary } from "@/lib/api"; import { formatDate } from "@/lib/utils"; export default function DashboardPage() { const [flows, setFlows] = useState(null); const [error, setError] = useState(null); const [health, setHealth] = useState<"ok" | "down" | "checking">("checking"); async function load() { try { const list = await api.listFlows(); list.sort((a, b) => (b.updatedAt || "").localeCompare(a.updatedAt || "")); setFlows(list); setError(null); } catch (e) { setError(e instanceof Error ? e.message : "failed to load"); } } useEffect(() => { load(); api .health() .then(() => setHealth("ok")) .catch(() => setHealth("down")); }, []); async function onDelete(id: string) { if (!confirm("Delete this pipeline?")) return; try { await api.deleteFlow(id); await load(); } catch (e) { alert(e instanceof Error ? e.message : "delete failed"); } } return (

Pipelines

Durable, n8n-compatible pipelines. Build on the canvas or paste exported JSON to import.

API {health}
{error && ( {error} )} {flows === null ? ( ) : flows.length === 0 ? ( ) : (
{flows.map((f) => (
{f.name || "Untitled pipeline"} {f.id}
{f.status || "draft"}
{f.nodeCount}{" "} nodes ยท {formatDate(f.updatedAt)}
))}
)}
); } function SkeletonGrid() { return (
{Array.from({ length: 3 }).map((_, i) => (
))}
); } function EmptyState() { return (

No pipelines yet

Build one on the canvas, or import an n8n workflow JSON.

); }