Building an Agent Admin Dashboard: React Components for Monitoring and Configuration
Design and build an admin dashboard for AI agents with metric cards, real-time charts, configuration panels, and activity logs using React, TypeScript, and TanStack Query.
What an Agent Dashboard Needs
An agent admin dashboard serves two audiences: operations teams monitoring agent health and behavior, and product teams configuring agent behavior. The dashboard must display key metrics at a glance, show conversation activity in real-time, surface errors and escalations, and provide configuration controls for agent parameters.
Dashboard Layout
Use a grid-based layout with a sidebar for navigation and a main content area divided into metric cards at the top and detailed panels below.
flowchart LR
INPUT(["User intent"])
PARSE["Parse plus<br/>classify"]
PLAN["Plan and tool<br/>selection"]
AGENT["Agent loop<br/>LLM plus tools"]
GUARD{"Guardrails<br/>and policy"}
EXEC["Execute and<br/>verify result"]
OBS[("Trace and metrics")]
OUT(["Outcome plus<br/>next action"])
INPUT --> PARSE --> PLAN --> AGENT --> GUARD
GUARD -->|Pass| EXEC --> OUT
GUARD -->|Fail| AGENT
AGENT --> OBS
style AGENT fill:#4f46e5,stroke:#4338ca,color:#fff
style GUARD fill:#f59e0b,stroke:#d97706,color:#1f2937
style OBS fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
style OUT fill:#059669,stroke:#047857,color:#fff
function AgentDashboard() {
return (
<div className="flex h-screen bg-gray-50">
<Sidebar />
<main className="flex-1 overflow-y-auto p-6">
<h1 className="text-2xl font-bold mb-6">Agent Overview</h1>
<MetricCardsRow />
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mt-6">
<ConversationChart />
<RecentActivity />
</div>
<AgentConfigPanel />
</main>
</div>
);
}
Metric Cards with Real-Time Data
Metric cards show the most important numbers: total conversations, average response time, error rate, and user satisfaction score. Fetch these with TanStack Query for automatic background refetching.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
import { useQuery } from "@tanstack/react-query";
interface AgentMetrics {
totalConversations: number;
avgResponseTimeMs: number;
errorRate: number;
satisfactionScore: number;
}
function MetricCardsRow() {
const { data, isLoading } = useQuery<AgentMetrics>({
queryKey: ["agent-metrics"],
queryFn: () =>
fetch("/api/admin/metrics").then((r) => r.json()),
refetchInterval: 30_000, // Refresh every 30 seconds
});
if (isLoading) return <MetricCardsSkeleton />;
return (
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
<MetricCard
label="Conversations"
value={data!.totalConversations.toLocaleString()}
trend="+12%"
trendUp={true}
/>
<MetricCard
label="Avg Response"
value={`${(data!.avgResponseTimeMs / 1000).toFixed(1)}s`}
trend="-8%"
trendUp={true}
/>
<MetricCard
label="Error Rate"
value={`${(data!.errorRate * 100).toFixed(2)}%`}
trend="+0.3%"
trendUp={false}
/>
<MetricCard
label="Satisfaction"
value={`${data!.satisfactionScore.toFixed(1)}/5`}
trend="+0.2"
trendUp={true}
/>
</div>
);
}
The Metric Card Component
Each card displays a label, value, and trend indicator. The trend arrow and color change based on whether the direction is positive or negative.
interface MetricCardProps {
label: string;
value: string;
trend: string;
trendUp: boolean;
}
function MetricCard({ label, value, trend, trendUp }: MetricCardProps) {
return (
<div className="bg-white rounded-xl border p-5">
<p className="text-sm text-gray-500 mb-1">{label}</p>
<p className="text-2xl font-bold text-gray-900">{value}</p>
<p
className={`text-sm mt-2 ${
trendUp ? "text-green-600" : "text-red-600"
}`}
>
{trendUp ? "^" : "v"} {trend} vs last week
</p>
</div>
);
}
Skeleton Loading States
Dashboard components should show skeleton placeholders during data loading instead of blank space. This prevents layout shift and communicates that data is on the way.
function MetricCardsSkeleton() {
return (
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
{Array.from({ length: 4 }).map((_, i) => (
<div key={i} className="bg-white rounded-xl border p-5">
<div className="h-4 w-20 bg-gray-200 rounded animate-pulse mb-2" />
<div className="h-8 w-24 bg-gray-200 rounded animate-pulse mb-2" />
<div className="h-3 w-28 bg-gray-200 rounded animate-pulse" />
</div>
))}
</div>
);
}
Recent Activity Feed
An activity log shows recent conversations, errors, and escalations in chronological order. Use a polling query to keep it up-to-date.
interface ActivityItem {
id: string;
type: "conversation" | "error" | "escalation";
summary: string;
timestamp: string;
}
function RecentActivity() {
const { data } = useQuery<ActivityItem[]>({
queryKey: ["agent-activity"],
queryFn: () =>
fetch("/api/admin/activity?limit=20").then((r) => r.json()),
refetchInterval: 10_000,
});
const typeStyles: Record<ActivityItem["type"], string> = {
conversation: "bg-blue-100 text-blue-700",
error: "bg-red-100 text-red-700",
escalation: "bg-yellow-100 text-yellow-700",
};
return (
<div className="bg-white rounded-xl border p-5">
<h2 className="font-semibold text-lg mb-4">Recent Activity</h2>
<div className="space-y-3 max-h-80 overflow-y-auto">
{data?.map((item) => (
<div key={item.id} className="flex items-start gap-3">
<span
className={`text-xs px-2 py-0.5 rounded-full
font-medium ${typeStyles[item.type]}`}
>
{item.type}
</span>
<div className="flex-1 min-w-0">
<p className="text-sm text-gray-700 truncate">
{item.summary}
</p>
<p className="text-xs text-gray-400">{item.timestamp}</p>
</div>
</div>
))}
</div>
</div>
);
}
Agent Configuration Panel
Allow admins to tweak agent parameters like system prompt, temperature, max tokens, and enabled tools without deploying code.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
import { useMutation, useQueryClient } from "@tanstack/react-query";
interface AgentConfig {
systemPrompt: string;
temperature: number;
maxTokens: number;
enabledTools: string[];
}
function AgentConfigPanel() {
const queryClient = useQueryClient();
const { data: config } = useQuery<AgentConfig>({
queryKey: ["agent-config"],
queryFn: () =>
fetch("/api/admin/config").then((r) => r.json()),
});
const mutation = useMutation({
mutationFn: (updated: AgentConfig) =>
fetch("/api/admin/config", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(updated),
}),
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: ["agent-config"] }),
});
if (!config) return null;
return (
<div className="bg-white rounded-xl border p-6 mt-6">
<h2 className="font-semibold text-lg mb-4">
Agent Configuration
</h2>
<label className="block text-sm font-medium mb-1">
System Prompt
</label>
<textarea
defaultValue={config.systemPrompt}
rows={4}
className="w-full border rounded-lg p-3 text-sm mb-4"
/>
<button
onClick={() => mutation.mutate(config)}
className="bg-blue-600 text-white px-4 py-2 rounded-lg
text-sm disabled:opacity-50"
disabled={mutation.isPending}
>
{mutation.isPending ? "Saving..." : "Save Changes"}
</button>
</div>
);
}
FAQ
How do I add charts to the dashboard?
Use a charting library like Recharts or Chart.js with a React wrapper. Fetch time-series data from your API (grouped by hour or day) and pass it to a line or bar chart component. Recharts integrates naturally with React because its charts are composed from React components like <LineChart>, <Line>, and <XAxis>.
Should I use WebSockets or polling for real-time dashboard updates?
Polling with TanStack Query's refetchInterval is simpler and works well for dashboards where 10-30 second latency is acceptable. Use WebSockets only if you need sub-second updates, such as live conversation transcripts or real-time error alerts that require immediate operator attention.
How do I restrict dashboard access to admin users?
Wrap your dashboard routes in an authentication guard that checks the user's role. In Next.js, use middleware to redirect non-admin users before the page loads. On the API side, every admin endpoint should verify the JWT token contains an admin role claim and return 403 if it does not.
#AdminDashboard #React #Monitoring #TypeScript #AIAgentManagement #AgenticAI #LearnAI #AIEngineering
Try CallSphere AI Voice Agents
See how AI voice agents work for your industry. Live demo available -- no signup required.