AgentGraph / frontend /src /hooks /useDashboardData.ts
wu981526092's picture
🚀 Deploy AgentGraph: Complete agent monitoring and knowledge graph system
c2ea5ed
import { useState, useEffect, useCallback, useMemo } from "react";
import { useAgentGraph } from "@/context/AgentGraphContext";
interface DashboardStats {
totalTraces: number;
totalAgentGraphs: number;
totalEntities: number;
totalRelations: number;
completedProcessing: number;
processingProgress: number;
systemStatus: "healthy" | "warning" | "error";
}
interface ActivityItem {
id: string;
action: string;
trace: string;
timestamp: string;
status: "success" | "error" | "processing";
}
export function useDashboardData() {
const { state } = useAgentGraph();
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
// Calculate stats using useMemo to avoid unnecessary recalculations
const stats = useMemo<DashboardStats>(() => {
const totalTraces = state.traces.length;
const totalAgentGraphs = state.traces.reduce((total, trace) => {
// Count only final knowledge graphs (consistent with sidebar and main content)
const finalKGs =
trace.knowledge_graphs?.filter(
(kg) =>
kg.is_final === true ||
(kg.window_index === null && kg.window_total !== null)
) || [];
return total + finalKGs.length;
}, 0);
const totalEntities = state.traces.reduce((total, trace) => {
const entityCount =
trace.knowledge_graphs?.reduce((kgTotal, kg) => {
return kgTotal + (kg.entity_count || 0);
}, 0) || 0;
return total + entityCount;
}, 0);
const totalRelations = state.traces.reduce((total, trace) => {
const relationCount =
trace.knowledge_graphs?.reduce((kgTotal, kg) => {
return kgTotal + (kg.relation_count || 0);
}, 0) || 0;
return total + relationCount;
}, 0);
const completedProcessing = state.traces.reduce((total, trace) => {
const completedKGs =
trace.knowledge_graphs?.filter((kg) => kg.status === "analyzed") || [];
return total + completedKGs.length;
}, 0);
const processingProgress =
totalAgentGraphs > 0 ? (completedProcessing / totalAgentGraphs) * 100 : 0;
return {
totalTraces,
totalAgentGraphs,
totalEntities,
totalRelations,
completedProcessing,
processingProgress,
systemStatus: "healthy",
};
}, [state.traces]);
// Calculate recent activity using useMemo
const recentActivity = useMemo<ActivityItem[]>(() => {
const activity: ActivityItem[] = [];
// Add recent trace uploads
state.traces.slice(0, 2).forEach((trace) => {
activity.push({
id: `trace-${trace.id}`,
action: "Trace Uploaded",
trace: trace.filename,
timestamp: getRelativeTime(
trace.update_timestamp || trace.upload_timestamp || ""
),
status: "success",
});
});
// Add recent graph generations from traces
const allKnowledgeGraphs = state.traces.flatMap(
(trace) => trace.knowledge_graphs || []
);
allKnowledgeGraphs
.sort((a, b) => {
const dateA = new Date(a.created_at || 0);
const dateB = new Date(b.created_at || 0);
return dateB.getTime() - dateA.getTime();
})
.slice(0, 2)
.forEach((kg, index) => {
activity.push({
id: `kg-${kg.kg_id || kg.id || index}`,
action: "Agent Graph Generated",
trace: kg.filename || "Unknown",
timestamp: getRelativeTime(kg.created_at),
status: kg.status === "analyzed" ? "success" : "processing",
});
});
return activity.slice(0, 5);
}, [state.traces]);
const fetchDashboardData = useCallback(async () => {
try {
setIsLoading(true);
setError(null);
// Data is now calculated via useMemo, so we just need to handle loading state
setIsLoading(false);
} catch (err) {
setError(
err instanceof Error ? err.message : "Failed to load dashboard data"
);
setIsLoading(false);
}
}, []);
useEffect(() => {
fetchDashboardData();
}, [fetchDashboardData]);
return {
stats,
recentActivity,
isLoading,
error,
refresh: fetchDashboardData,
};
}
function getRelativeTime(dateString: string): string {
const date = new Date(dateString);
const now = new Date();
const diffMs = now.getTime() - date.getTime();
// If the date is invalid, return a default
if (isNaN(diffMs)) return "Recently";
const diffMins = Math.floor(diffMs / 60000);
const diffHours = Math.floor(diffMs / 3600000);
const diffDays = Math.floor(diffMs / 86400000);
if (diffMins < 1) return "Just now";
if (diffMins < 60) return `${diffMins} minute${diffMins > 1 ? "s" : ""} ago`;
if (diffHours < 24) return `${diffHours} hour${diffHours > 1 ? "s" : ""} ago`;
return `${diffDays} day${diffDays > 1 ? "s" : ""} ago`;
}