diff --git a/packages/dashboard/src/app/page.tsx b/packages/dashboard/src/app/page.tsx
index 27911c2..1efd84d 100644
--- a/packages/dashboard/src/app/page.tsx
+++ b/packages/dashboard/src/app/page.tsx
@@ -1,9 +1,11 @@
"use client";
import { useEffect, useState, useCallback } from "react";
+import { DEMO_AGENTS, DEMO_METRICS, DEMO_TASKS, DEMO_DLQ } from "../lib/mock-data";
const API_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:3000";
const WS_URL = process.env.NEXT_PUBLIC_WS_URL || "ws://localhost:3000/ws";
+const IS_DEMO = process.env.NEXT_PUBLIC_DEMO === "true" || typeof window !== "undefined";
interface Agent {
id: string;
@@ -78,10 +80,19 @@ export default function Dashboard() {
if (metricsRes.status === "fulfilled") setMetrics(metricsRes.value.data);
if (tasksRes.status === "fulfilled") setTasks(tasksRes.value.data);
if (dlqRes.status === "fulfilled") setDlq(dlqRes.value.data);
+ } catch {
+ // Fallback to demo data when API is unavailable
+ if (IS_DEMO && agents.length === 0) {
+ setAgents(DEMO_AGENTS);
+ setMetrics(DEMO_METRICS);
+ setTasks(DEMO_TASKS);
+ setDlq(DEMO_DLQ);
+ setConnected(true);
+ }
} finally {
setLoading(false);
}
- }, []);
+ }, [agents.length]);
useEffect(() => {
let ws: WebSocket | null = null;
@@ -156,6 +167,9 @@ export default function Dashboard() {
+ {IS_DEMO && agents.length > 0 && (
+
DEMO
+ )}
{connected ? "Live" : "Offline"}
diff --git a/packages/dashboard/src/lib/mock-data.ts b/packages/dashboard/src/lib/mock-data.ts
new file mode 100644
index 0000000..4724fcc
--- /dev/null
+++ b/packages/dashboard/src/lib/mock-data.ts
@@ -0,0 +1,104 @@
+/** Mock data for demo mode — used when API is unavailable */
+
+export const DEMO_AGENTS = [
+ {
+ id: "http-worker-1",
+ definitionId: "http-worker-1",
+ status: "running" as const,
+ startedAt: new Date(Date.now() - 3600000 * 4.2).toISOString(),
+ lastHeartbeat: new Date().toISOString(),
+ tasksProcessed: 1847,
+ tasksFailed: 23,
+ currentTask: null,
+ memoryUsage: 67 * 1024 * 1024,
+ uptime: 3600000 * 4.2,
+ lastError: null,
+ },
+ {
+ id: "http-worker-2",
+ definitionId: "http-worker-2",
+ status: "running" as const,
+ startedAt: new Date(Date.now() - 3600000 * 4.2).toISOString(),
+ lastHeartbeat: new Date().toISOString(),
+ tasksProcessed: 1523,
+ tasksFailed: 12,
+ currentTask: "task-a8f2c1",
+ memoryUsage: 54 * 1024 * 1024,
+ uptime: 3600000 * 4.2,
+ lastError: null,
+ },
+ {
+ id: "scheduler-1",
+ definitionId: "scheduler-1",
+ status: "running" as const,
+ startedAt: new Date(Date.now() - 3600000 * 8).toISOString(),
+ lastHeartbeat: new Date().toISOString(),
+ tasksProcessed: 492,
+ tasksFailed: 0,
+ currentTask: null,
+ memoryUsage: 32 * 1024 * 1024,
+ uptime: 3600000 * 8,
+ lastError: null,
+ },
+ {
+ id: "watchdog-1",
+ definitionId: "watchdog-1",
+ status: "running" as const,
+ startedAt: new Date(Date.now() - 3600000 * 8).toISOString(),
+ lastHeartbeat: new Date().toISOString(),
+ tasksProcessed: 156,
+ tasksFailed: 0,
+ currentTask: null,
+ memoryUsage: 28 * 1024 * 1024,
+ uptime: 3600000 * 8,
+ lastError: null,
+ },
+ {
+ id: "analytics-1",
+ definitionId: "analytics-1",
+ status: "paused" as const,
+ startedAt: new Date(Date.now() - 3600000 * 2).toISOString(),
+ lastHeartbeat: new Date(Date.now() - 60000).toISOString(),
+ tasksProcessed: 89,
+ tasksFailed: 3,
+ currentTask: null,
+ memoryUsage: 41 * 1024 * 1024,
+ uptime: 3600000 * 2,
+ lastError: null,
+ },
+ {
+ id: "retry-agent",
+ definitionId: "retry-agent",
+ status: "idle" as const,
+ startedAt: null,
+ lastHeartbeat: null,
+ tasksProcessed: 0,
+ tasksFailed: 0,
+ currentTask: null,
+ memoryUsage: 0,
+ uptime: 0,
+ lastError: null,
+ },
+];
+
+export const DEMO_METRICS = {
+ agents: { total: 6, running: 4, failed: 0, idle: 1 },
+ performance: { totalProcessed: 4107, totalFailed: 38, avgUptime: 21600000, totalMemoryMb: 222 },
+ system: { nodeVersion: "v20.18.0", uptime: 28800, memoryMb: 156 },
+};
+
+export const DEMO_TASKS = [
+ { id: "tsk_a8f2c1d9", agentId: "http-worker-2", type: "health_check", status: "processing", priority: "high", attempts: 0, createdAt: new Date().toISOString() },
+ { id: "tsk_b3e7a2f0", agentId: "http-worker-1", type: "api_monitor", status: "completed", priority: "normal", attempts: 1, createdAt: new Date(Date.now() - 15000).toISOString() },
+ { id: "tsk_c9d1f4e8", agentId: "scheduler-1", type: "cron_trigger", status: "completed", priority: "normal", attempts: 0, createdAt: new Date(Date.now() - 30000).toISOString() },
+ { id: "tsk_d2a6b8c3", agentId: "http-worker-1", type: "webhook_dispatch", status: "completed", priority: "high", attempts: 0, createdAt: new Date(Date.now() - 45000).toISOString() },
+ { id: "tsk_e7f0c1a5", agentId: "http-worker-2", type: "data_sync", status: "completed", priority: "low", attempts: 0, createdAt: new Date(Date.now() - 60000).toISOString() },
+ { id: "tsk_f1b9d4e2", agentId: "watchdog-1", type: "agent_health", status: "completed", priority: "critical", attempts: 0, createdAt: new Date(Date.now() - 90000).toISOString() },
+ { id: "tsk_g4c8a3f7", agentId: "http-worker-1", type: "api_monitor", status: "failed", priority: "normal", attempts: 3, createdAt: new Date(Date.now() - 120000).toISOString() },
+ { id: "tsk_h6d2b5e1", agentId: "analytics-1", type: "report_gen", status: "completed", priority: "low", attempts: 0, createdAt: new Date(Date.now() - 180000).toISOString() },
+];
+
+export const DEMO_DLQ = [
+ { id: "tsk_x1y2z3", agentId: "http-worker-1", type: "webhook_dispatch", status: "dead_letter", priority: "high", attempts: 3, createdAt: new Date(Date.now() - 300000).toISOString() },
+ { id: "tsk_x4y5z6", agentId: "http-worker-2", type: "api_monitor", status: "dead_letter", priority: "normal", attempts: 3, createdAt: new Date(Date.now() - 600000).toISOString() },
+];