Operations dashboard
A dark service-health dashboard with SVG sparklines, status indicators, and a filterable incident table.
A second dashboard variant focused on monitoring rather than business metrics. Each service card shows current latency, a dependency-free SVG sparkline of the last 24 samples and an error rate; the incident table filters by status. A 'simulate live updates' toggle re-samples the local data every two seconds so you can see how the UI behaves with changing values before connecting a real metrics endpoint.
- react
- dashboard
- monitoring
- charts
- dark-mode
- tailwind
This preview is the template's actual file tree and source code — exactly what is copied into a new project. Codexa does not publish screenshots or mock-ups of templates; run the project to see it rendered.
Files11 files
import { useEffect, useState } from "react";
import { incidents as seedIncidents, services as seedServices, tick, type Incident, type Service } from "./data";
import { Sparkline } from "./Sparkline";
const statusColor: Record<Service["status"], string> = { operational: "bg-green-500", degraded: "bg-amber-500", down: "bg-red-500" };
const incidentFilters: ("all" | Incident["status"])[] = ["all", "open", "monitoring", "resolved"];
export default function App() {
const [services, setServices] = useState<Service[]>(seedServices);
const [live, setLive] = useState(false);
const [filter, setFilter] = useState<(typeof incidentFilters)[number]>("all");
useEffect(() => {
if (!live) return;
const id = window.setInterval(() => setServices((s) => tick(s)), 2000);
return () => window.clearInterval(id);
}, [live]);
const visibleIncidents = seedIncidents.filter((i) => filter === "all" || i.status === filter);
const degraded = services.filter((s) => s.status !== "operational").length;
return (
<div className="min-h-screen bg-zinc-950 text-zinc-100">
<header className="border-b border-zinc-800 px-4 py-3 sm:px-6">
<div className="mx-auto flex max-w-6xl flex-wrap items-center justify-between gap-3">
<h1 className="font-semibold tracking-tight">Operations</h1>
<label className="flex items-center gap-2 text-sm text-zinc-400">
<input type="checkbox" checked={live} onChange={(e) => setLive(e.target.checked)} />
Simulate live updates
</label>
</div>
</header>
<main className="mx-auto max-w-6xl px-4 py-6 sm:px-6">
<p className="text-sm text-zinc-400" role="status">
{degraded === 0 ? "All systems operational." : degraded + " service" + (degraded === 1 ? "" : "s") + " degraded."}
</p>
<section aria-labelledby="services-title" className="mt-4">
<h2 id="services-title" className="text-sm font-medium uppercase tracking-wide text-zinc-500">
Services
</h2>
<ul className="mt-3 grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
{services.map((s) => {
const last = s.latencyMs[s.latencyMs.length - 1] ?? 0;
return (
<li key={s.name} className="rounded-xl border border-zinc-800 bg-zinc-900 p-4">
<div className="flex items-center justify-between">
<h3 className="font-medium">{s.name}</h3>
<span className="flex items-center gap-1.5 text-xs capitalize text-zinc-400">
<span aria-hidden="true" className={"size-2 rounded-full " + statusColor[s.status]} />
{s.status}
</span>
</div>
<p className="mt-3 text-2xl font-semibold tabular-nums">
{last}
<span className="text-sm font-normal text-zinc-500"> ms</span>
</p>
<Sparkline values={s.latencyMs} label={s.name + " latency over the last 24 samples"} className="mt-2 text-sky-400" />
<p className="mt-2 text-xs text-zinc-500">Error rate {s.errorRate.toFixed(1)}%</p>
</li>
);
})}
</ul>
</section>
<section aria-labelledby="incidents-title" className="mt-10">
<div className="flex flex-wrap items-center justify-between gap-3">
<h2 id="incidents-title" className="text-sm font-medium uppercase tracking-wide text-zinc-500">
Incidents
</h2>
<div className="flex gap-1 rounded-md border border-zinc-800 p-0.5" role="group" aria-label="Filter incidents">
{incidentFilters.map((f) => (
<button key={f} type="button" onClick={() => setFilter(f)} aria-pressed={filter === f} className={"rounded px-2.5 py-1 text-xs capitalize " + (filter === f ? "bg-zinc-100 text-zinc-900" : "text-zinc-400 hover:text-zinc-100")}>
{f}
</button>
))}
</div>
</div>
<div className="mt-3 overflow-x-auto rounded-xl border border-zinc-800">
<table className="w-full min-w-[560px] text-sm">
<thead className="bg-zinc-900 text-left text-zinc-400">
<tr>
<th className="p-3">ID</th>
<th className="p-3">Title</th>
<th className="p-3">Service</th>
<th className="p-3">Status</th>
<th className="p-3">Opened</th>
</tr>
</thead>
<tbody>
{visibleIncidents.map((i) => (
<tr key={i.id} className="border-t border-zinc-800">
<td className="p-3 font-mono text-xs text-zinc-400">{i.id}</td>
<td className="p-3">{i.title}</td>
<td className="p-3 text-zinc-400">{i.service}</td>
<td className="p-3 capitalize">{i.status}</td>
<td className="p-3 text-zinc-400">{new Date(i.openedAt).toLocaleString()}</td>
</tr>
))}
{visibleIncidents.length === 0 ? (
<tr>
<td colSpan={5} className="p-6 text-center text-zinc-500">
No incidents with this status.
</td>
</tr>
) : null}
</tbody>
</table>
</div>
</section>
</main>
</div>
);
}
Dependencies
Documented from the template's package.json. The runtime has a prebuilt dependency set for Vite + React + TypeScript, so installs are fast.
| Package | Version |
|---|---|
| react | ^19.1.0 |
| react-dom | ^19.1.0 |
| vite | ^6.3.0 |
| @vitejs/plugin-react | ^4.4.0 |
| tailwindcss | ^4.1.0 |
| @tailwindcss/vite | ^4.1.0 |
| typescript | ^5.8.0 |
How it runs
- Framework
- Vite + React + TypeScript
- Dev command
- npm run dev
- Build command
- npm run build
- Output directory
- dist
- Port
- 5173
- Opens at
- /
- Difficulty
- intermediate
Projects run in an isolated sandbox with a live preview. Read the projects documentation for details on settings, snapshots and deployment.
More dashboards templates
View all- Framework: Vite + React + TypeScriptDifficulty: intermediateFeatured
Analytics dashboard
A responsive dashboard layout with sidebar navigation, stat cards, and a data table.
- react
- dashboard
- tailwind
- table
9 files
Need the raw data? GET /api/v1/templates/vite-react-ops-dashboard returns this template with its files.
Build on Operations dashboard
Create a free account, start from this template, and ask the AI agent to turn it into your app.