More Dashboards Snippets
System Status Dashboard — Uptime Widget HTML CSS JS
System Status Dashboard Widget · Dashboards · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
System Status Dashboard — 90-Day Uptime Bars, Status Badges & Incident Callout

A system status dashboard communicates service health to end users, support teams, and stakeholders. It answers three questions instantly: is everything working right now, which services have had issues recently, and is there an active incident being worked on? This snippet implements a complete status page widget with six service rows, 30-bar uptime histograms, colour-coded status badges, an active incident callout box, and an animated pulsing dot for live outages.
Uptime bar chart generation
The 30 uptime bars are generated programmatically from a DATA object mapping service IDs to arrays of 30 values (0–1). A value of 1 means fully operational, 0 means outage, and intermediate values represent degraded performance. JavaScript creates one <div class="bar"> per value, sets its height proportionally (Math.max(8, Math.round(v * 24))px), and adds class out or deg for colouring. The minimum height of 8px ensures that even zero-uptime days are visible as a thin red bar rather than disappearing entirely.
Status colour system
Three states use a consistent colour system across the entire component: green (#22c55e) for operational, amber (#f59e0b) for degraded, red (#ef4444) for outage. Each state has a badge variant (light background tint + dark text), a dot variant (solid circle), and a bar variant (coloured fill). By using the same three colours throughout, users can instantly scan the entire page and understand the pattern without reading every label.
Animated outage pulse
The outage dot uses a CSS @keyframes pulse animation that cycles opacity between 1 and 0.4 every 1.2 seconds. This mimics the "live" indicator pattern used in broadcast media and emergency dashboards — the motion attracts attention to the one service that needs immediate focus. Only the outage dot pulses; operational and degraded dots are static, so the animation carries signal rather than noise.
Incident callout box
When an incident is active, an amber callout box below the service list provides human-readable context: what is affected, the current status (investigating/monitoring/resolved), and time since the incident started. The warm orange palette (#fff7ed background, #fed7aa border) visually connects to the amber degraded state but is distinct from the red outage badges — it signals "something is being worked on" rather than "everything is broken".
Service row layout
Each service row is a flex container with three zones: left (dot + service name + latency), center (uptime bar chart), right (badge + percentage). The center zone has flex: 1 so it expands to fill available space. The right zone has min-width: 88px and text-align: right to keep badges and percentages aligned across rows. The left zone has min-width: 150px to prevent service names from wrapping.
React integration
Define a SERVICES array where each entry has id, name, latency, status, uptime (percentage string), and bars (30-element array). Map over it to render <ServiceRow /> components. The uptime bars render inside a useEffect or directly as JSX with .map() — prefer JSX mapping over imperative DOM manipulation in React. The active incident can be a separate incident prop on the parent StatusDashboard component.
Real-world integration
In production, replace the hardcoded DATA object with API responses from a status monitoring service (Betterstack, PagerDuty, or your own health-check endpoints). Poll every 30 seconds with setInterval and update the bars array. Store historical uptime in a time-series database and query the last 90 days on page load. The visual component stays identical — only the data source changes.
See also the metric card grid snippet for KPI dashboards, the line chart widget snippet for time-series data visualization, and the activity heatmap snippet for calendar-based uptime visualization.
Step by step
How to Use
- 1Copy the full HTML structureThe status page needs all sections: .status-header, .services-list, .incident-box, and .status-footer. The JS targets elements by ID so keep all IDs intact.
- 2Update service names and dataEdit the service names in .svc-name spans and update the DATA object in JS. Each entry maps a bars-{id} element ID to a 30-element array of 0–1 values.
- 3Set the overall statusChange .overall-dot class between operational, degraded, and outage. Update the .overall-title text and .uptime-global percentage to match current reality.
- 4Manage the incident boxShow or hide .incident-box based on whether an active incident exists. Update the .inc-body text and .inc-meta timestamp when incidents occur.
- 5Connect to a real monitoring APIReplace the hardcoded DATA with a fetch to your health-check API. Poll every 30 seconds with setInterval and re-render bars to reflect live uptime data.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
Define a SERVICES array with name, status, latency, uptime, and bars props. Map over it to render ServiceRow components. Render bars as JSX map instead of imperative DOM creation.
Replace the DATA object with a fetch call to your health-check endpoint. Use setInterval to poll every 30 seconds and update the bars array and status badges dynamically.
Add a status field to the incident data (active/monitoring/resolved). Use conditional CSS classes: green border for resolved, amber for monitoring, red for active.
Yes — just change the data granularity. Use 24 values for 24-hour view or 168 for 7-day hourly. Adjust the bar width by changing the gap and removing flex:1 for fixed pixel widths.
Open the Export menu (or the Test Exports preview) in the snippet toolbar. It generates a plain React component, a React + Tailwind version where the row, badge, and bar styles become utility classes, a Vue 3 single-file component, and an Angular standalone component. Each converter preserves the markup, the uptime-bar layout, and the outage-pulse animation, so the dashboard renders identically across React, Vue, and Angular. For production, drive the SERVICES array from your health-check API and poll it inside the framework lifecycle (useEffect, onMounted, or ngOnInit) instead of the hardcoded DATA object.
Average each service uptime, or weight by request volume if you have it, then format to two decimals such as 99.97%. For the 90-day bars, derive the figure from the count of operational versus degraded or outage segments so the headline number always matches the visual history users can see in the chart.
System Status Dashboard Widget — Export as HTML, React, Vue, Angular & Tailwind
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>System Status Dashboard Widget</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; background: #f8fafc; min-height: 100vh; padding: 24px 16px; }
.page { max-width: 600px; margin: 0 auto; display: flex; flex-direction: column; gap: 16px; }
.status-header { background: #fff; border: 1.5px solid #e2e8f0; border-radius: 14px; padding: 18px 20px; }
.header-top { display: flex; align-items: center; gap: 14px; }
.overall-dot { width: 14px; height: 14px; border-radius: 50%; flex-shrink: 0; }
.overall-dot.operational { background: #22c55e; box-shadow: 0 0 0 4px #dcfce7; }
.overall-dot.degraded { background: #f59e0b; box-shadow: 0 0 0 4px #fef9c3; }
.overall-dot.outage { background: #ef4444; box-shadow: 0 0 0 4px #fee2e2; }
.overall-title { font-size: 16px; font-weight: 800; color: #111827; margin-bottom: 2px; }
.overall-sub { font-size: 12px; color: #6b7280; }
.uptime-global { color: #16a34a; font-weight: 600; }
.services-list { background: #fff; border: 1.5px solid #e2e8f0; border-radius: 14px; overflow: hidden; }
.service-row { display: flex; align-items: center; gap: 12px; padding: 13px 18px; border-bottom: 1px solid #f3f4f6; }
.service-row:last-child { border-bottom: none; }
.svc-left { display: flex; align-items: center; gap: 10px; min-width: 150px; }
.svc-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.svc-dot.op { background: #22c55e; }
.svc-dot.deg { background: #f59e0b; }
.svc-dot.out { background: #ef4444; animation: pulse 1.2s infinite; }
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.4} }
.svc-name { font-size: 13px; font-weight: 600; color: #111827; }
.svc-latency { font-size: 10px; color: #9ca3af; }
.uptime-bars { flex: 1; display: flex; gap: 2px; align-items: flex-end; height: 24px; }
.uptime-bars .bar { flex: 1; border-radius: 2px; background: #22c55e; max-height: 24px; min-height: 8px; }
.uptime-bars .bar.out { background: #ef4444; }
.uptime-bars .bar.deg { background: #f59e0b; }
.svc-right { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; min-width: 88px; }
.svc-badge { font-size: 10px; font-weight: 700; padding: 2px 8px; border-radius: 20px; }
.op-badge { background: #dcfce7; color: #15803d; }
.deg-badge { background: #fef9c3; color: #a16207; }
.out-badge { background: #fee2e2; color: #dc2626; }
.svc-pct { font-size: 11px; font-weight: 600; color: #374151; }
.incident-box { background: #fff7ed; border: 1.5px solid #fed7aa; border-radius: 14px; padding: 14px 18px; }
.inc-title { display: flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 700; color: #c2410c; margin-bottom: 7px; }
.inc-body { font-size: 12px; color: #7c2d12; line-height: 1.6; margin-bottom: 6px; }
.inc-meta { font-size: 11px; color: #9a3412; }
.status-footer { display: flex; align-items: center; gap: 16px; padding: 4px 0; }
.legend-item { display: flex; align-items: center; gap: 5px; font-size: 11px; color: #6b7280; }
.leg-dot { width: 7px; height: 7px; border-radius: 50%; }
.leg-dot.op { background: #22c55e; }
.leg-dot.deg { background: #f59e0b; }
.leg-dot.out { background: #ef4444; }
.legend-right { margin-left: auto; }
</style>
</head>
<body>
<div class="page">
<div class="status-header">
<div class="header-top">
<div class="overall-dot operational"></div>
<div>
<h2 class="overall-title">All Systems Operational</h2>
<p class="overall-sub">Last checked: just now · <span class="uptime-global">99.97% uptime</span></p>
</div>
</div>
</div>
<div class="services-list">
<div class="service-row">
<div class="svc-left">
<span class="svc-dot op"></span>
<div>
<div class="svc-name">API Gateway</div>
<div class="svc-latency">42ms avg</div>
</div>
</div>
<div class="uptime-bars" id="bars-api"></div>
<div class="svc-right"><span class="svc-badge op-badge">Operational</span><span class="svc-pct">99.98%</span></div>
</div>
<div class="service-row">
<div class="svc-left">
<span class="svc-dot op"></span>
<div>
<div class="svc-name">Web Dashboard</div>
<div class="svc-latency">88ms avg</div>
</div>
</div>
<div class="uptime-bars" id="bars-web"></div>
<div class="svc-right"><span class="svc-badge op-badge">Operational</span><span class="svc-pct">99.95%</span></div>
</div>
<div class="service-row">
<div class="svc-left">
<span class="svc-dot deg"></span>
<div>
<div class="svc-name">CDN / Edge Network</div>
<div class="svc-latency">210ms avg</div>
</div>
</div>
<div class="uptime-bars" id="bars-cdn"></div>
<div class="svc-right"><span class="svc-badge deg-badge">Degraded</span><span class="svc-pct">98.40%</span></div>
</div>
<div class="service-row">
<div class="svc-left">
<span class="svc-dot op"></span>
<div>
<div class="svc-name">Database Cluster</div>
<div class="svc-latency">12ms avg</div>
</div>
</div>
<div class="uptime-bars" id="bars-db"></div>
<div class="svc-right"><span class="svc-badge op-badge">Operational</span><span class="svc-pct">100%</span></div>
</div>
<div class="service-row">
<div class="svc-left">
<span class="svc-dot op"></span>
<div>
<div class="svc-name">Auth Service</div>
<div class="svc-latency">31ms avg</div>
</div>
</div>
<div class="uptime-bars" id="bars-auth"></div>
<div class="svc-right"><span class="svc-badge op-badge">Operational</span><span class="svc-pct">99.99%</span></div>
</div>
<div class="service-row">
<div class="svc-left">
<span class="svc-dot out"></span>
<div>
<div class="svc-name">Webhooks</div>
<div class="svc-latency">— </div>
</div>
</div>
<div class="uptime-bars" id="bars-wh"></div>
<div class="svc-right"><span class="svc-badge out-badge">Outage</span><span class="svc-pct">95.10%</span></div>
</div>
</div>
<div class="incident-box">
<div class="inc-title">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
Active Incident
</div>
<p class="inc-body">Webhooks experiencing elevated failure rates. Engineering team investigating. CDN latency elevated in EU-West region.</p>
<div class="inc-meta">Started 14 min ago · Monitoring</div>
</div>
<div class="status-footer">
<span class="legend-item"><span class="leg-dot op"></span>Operational</span>
<span class="legend-item"><span class="leg-dot deg"></span>Degraded</span>
<span class="legend-item"><span class="leg-dot out"></span>Outage</span>
<span class="legend-item legend-right">90-day uptime</span>
</div>
</div>
<script>
const DATA = {
'bars-api': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.6,1],
'bars-web': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.7,1,1,1,1,1],
'bars-cdn': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.5,1,1,1,1,1,1,1,1,1,0.4,0.3,0.3,0.3],
'bars-db': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
'bars-auth':[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
'bars-wh': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.8,1,1,1,0.6,1,1,1,1,0.2,0.1,0,0,0,0]
};
Object.entries(DATA).forEach(([id, vals]) => {
const el = document.getElementById(id);
if (!el) return;
vals.forEach(v => {
const b = document.createElement('div');
b.className = 'bar' + (v === 0 ? ' out' : v < 0.5 ? ' deg' : '');
b.style.height = Math.max(8, Math.round(v * 24)) + 'px';
b.title = v === 1 ? 'Operational' : v === 0 ? 'Outage' : 'Degraded';
el.appendChild(b);
});
});
</script>
</body>
</html><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>System Status Dashboard Widget</title>
<!-- Tailwind CSS v3+ — arbitrary value classes (e.g. bg-[#0f172a]) are valid -->
<script src="https://cdn.tailwindcss.com"></script>
<style>
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.4} }
* {
box-sizing: border-box; margin: 0; padding: 0;
}
body {
font-family: system-ui, sans-serif; background: #f8fafc; min-height: 100vh; padding: 24px 16px;
}
.overall-dot.operational {
background: #22c55e; box-shadow: 0 0 0 4px #dcfce7;
}
.overall-dot.degraded {
background: #f59e0b; box-shadow: 0 0 0 4px #fef9c3;
}
.overall-dot.outage {
background: #ef4444; box-shadow: 0 0 0 4px #fee2e2;
}
.service-row:last-child {
border-bottom: none;
}
.svc-dot.op {
background: #22c55e;
}
.svc-dot.deg {
background: #f59e0b;
}
.svc-dot.out {
background: #ef4444; animation: pulse 1.2s infinite;
}
.uptime-bars .bar {
flex: 1; border-radius: 2px; background: #22c55e; max-height: 24px; min-height: 8px;
}
.uptime-bars .bar.out {
background: #ef4444;
}
.uptime-bars .bar.deg {
background: #f59e0b;
}
.leg-dot.op {
background: #22c55e;
}
.leg-dot.deg {
background: #f59e0b;
}
.leg-dot.out {
background: #ef4444;
}
</style>
</head>
<body>
<div class="max-w-[600px] my-0 mx-auto flex flex-col gap-4">
<div class="bg-[#fff] border rounded-[14px] py-[18px] px-5">
<div class="flex items-center gap-3.5">
<div class="overall-dot w-3.5 h-3.5 rounded-full shrink-0 operational"></div>
<div>
<h2 class="text-base font-extrabold text-[#111827] mb-0.5">All Systems Operational</h2>
<p class="text-xs text-[#6b7280]">Last checked: just now · <span class="text-[#16a34a] font-semibold">99.97% uptime</span></p>
</div>
</div>
</div>
<div class="bg-[#fff] border rounded-[14px] overflow-hidden">
<div class="service-row flex items-center gap-3 py-[13px] px-[18px] border-b border-b-[#f3f4f6]">
<div class="flex items-center gap-2.5 min-w-[150px]">
<span class="svc-dot w-2 h-2 rounded-full shrink-0 op"></span>
<div>
<div class="text-[13px] font-semibold text-[#111827]">API Gateway</div>
<div class="text-xs text-[#9ca3af]">42ms avg</div>
</div>
</div>
<div class="uptime-bars flex-1 flex gap-0.5 items-end h-6" id="bars-api"></div>
<div class="flex flex-col items-end gap-[3px] min-w-[88px]"><span class="text-xs font-bold py-0.5 px-2 rounded-[20px] bg-[#dcfce7] text-[#15803d]">Operational</span><span class="text-[11px] font-semibold text-[#374151]">99.98%</span></div>
</div>
<div class="service-row flex items-center gap-3 py-[13px] px-[18px] border-b border-b-[#f3f4f6]">
<div class="flex items-center gap-2.5 min-w-[150px]">
<span class="svc-dot w-2 h-2 rounded-full shrink-0 op"></span>
<div>
<div class="text-[13px] font-semibold text-[#111827]">Web Dashboard</div>
<div class="text-xs text-[#9ca3af]">88ms avg</div>
</div>
</div>
<div class="uptime-bars flex-1 flex gap-0.5 items-end h-6" id="bars-web"></div>
<div class="flex flex-col items-end gap-[3px] min-w-[88px]"><span class="text-xs font-bold py-0.5 px-2 rounded-[20px] bg-[#dcfce7] text-[#15803d]">Operational</span><span class="text-[11px] font-semibold text-[#374151]">99.95%</span></div>
</div>
<div class="service-row flex items-center gap-3 py-[13px] px-[18px] border-b border-b-[#f3f4f6]">
<div class="flex items-center gap-2.5 min-w-[150px]">
<span class="svc-dot w-2 h-2 rounded-full shrink-0 deg"></span>
<div>
<div class="text-[13px] font-semibold text-[#111827]">CDN / Edge Network</div>
<div class="text-xs text-[#9ca3af]">210ms avg</div>
</div>
</div>
<div class="uptime-bars flex-1 flex gap-0.5 items-end h-6" id="bars-cdn"></div>
<div class="flex flex-col items-end gap-[3px] min-w-[88px]"><span class="text-xs font-bold py-0.5 px-2 rounded-[20px] bg-[#fef9c3] text-[#a16207]">Degraded</span><span class="text-[11px] font-semibold text-[#374151]">98.40%</span></div>
</div>
<div class="service-row flex items-center gap-3 py-[13px] px-[18px] border-b border-b-[#f3f4f6]">
<div class="flex items-center gap-2.5 min-w-[150px]">
<span class="svc-dot w-2 h-2 rounded-full shrink-0 op"></span>
<div>
<div class="text-[13px] font-semibold text-[#111827]">Database Cluster</div>
<div class="text-xs text-[#9ca3af]">12ms avg</div>
</div>
</div>
<div class="uptime-bars flex-1 flex gap-0.5 items-end h-6" id="bars-db"></div>
<div class="flex flex-col items-end gap-[3px] min-w-[88px]"><span class="text-xs font-bold py-0.5 px-2 rounded-[20px] bg-[#dcfce7] text-[#15803d]">Operational</span><span class="text-[11px] font-semibold text-[#374151]">100%</span></div>
</div>
<div class="service-row flex items-center gap-3 py-[13px] px-[18px] border-b border-b-[#f3f4f6]">
<div class="flex items-center gap-2.5 min-w-[150px]">
<span class="svc-dot w-2 h-2 rounded-full shrink-0 op"></span>
<div>
<div class="text-[13px] font-semibold text-[#111827]">Auth Service</div>
<div class="text-xs text-[#9ca3af]">31ms avg</div>
</div>
</div>
<div class="uptime-bars flex-1 flex gap-0.5 items-end h-6" id="bars-auth"></div>
<div class="flex flex-col items-end gap-[3px] min-w-[88px]"><span class="text-xs font-bold py-0.5 px-2 rounded-[20px] bg-[#dcfce7] text-[#15803d]">Operational</span><span class="text-[11px] font-semibold text-[#374151]">99.99%</span></div>
</div>
<div class="service-row flex items-center gap-3 py-[13px] px-[18px] border-b border-b-[#f3f4f6]">
<div class="flex items-center gap-2.5 min-w-[150px]">
<span class="svc-dot w-2 h-2 rounded-full shrink-0 out"></span>
<div>
<div class="text-[13px] font-semibold text-[#111827]">Webhooks</div>
<div class="text-xs text-[#9ca3af]">— </div>
</div>
</div>
<div class="uptime-bars flex-1 flex gap-0.5 items-end h-6" id="bars-wh"></div>
<div class="flex flex-col items-end gap-[3px] min-w-[88px]"><span class="text-xs font-bold py-0.5 px-2 rounded-[20px] bg-[#fee2e2] text-[#dc2626]">Outage</span><span class="text-[11px] font-semibold text-[#374151]">95.10%</span></div>
</div>
</div>
<div class="bg-[#fff7ed] border rounded-[14px] py-3.5 px-[18px]">
<div class="flex items-center gap-[7px] text-[13px] font-bold text-[#c2410c] mb-[7px]">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
Active Incident
</div>
<p class="text-xs text-[#7c2d12] leading-[1.6] mb-1.5">Webhooks experiencing elevated failure rates. Engineering team investigating. CDN latency elevated in EU-West region.</p>
<div class="text-[11px] text-[#9a3412]">Started 14 min ago · Monitoring</div>
</div>
<div class="flex items-center gap-4 py-1 px-0">
<span class="flex items-center gap-[5px] text-[11px] text-[#6b7280]"><span class="leg-dot w-[7px] h-[7px] rounded-full op"></span>Operational</span>
<span class="flex items-center gap-[5px] text-[11px] text-[#6b7280]"><span class="leg-dot w-[7px] h-[7px] rounded-full deg"></span>Degraded</span>
<span class="flex items-center gap-[5px] text-[11px] text-[#6b7280]"><span class="leg-dot w-[7px] h-[7px] rounded-full out"></span>Outage</span>
<span class="flex items-center gap-[5px] text-[11px] text-[#6b7280] ml-auto">90-day uptime</span>
</div>
</div>
<script>
const DATA = {
'bars-api': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.6,1],
'bars-web': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.7,1,1,1,1,1],
'bars-cdn': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.5,1,1,1,1,1,1,1,1,1,0.4,0.3,0.3,0.3],
'bars-db': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
'bars-auth':[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
'bars-wh': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.8,1,1,1,0.6,1,1,1,1,0.2,0.1,0,0,0,0]
};
Object.entries(DATA).forEach(([id, vals]) => {
const el = document.getElementById(id);
if (!el) return;
vals.forEach(v => {
const b = document.createElement('div');
b.className = 'bar' + (v === 0 ? ' out' : v < 0.5 ? ' deg' : '');
b.style.height = Math.max(8, Math.round(v * 24)) + 'px';
b.title = v === 1 ? 'Operational' : v === 0 ? 'Outage' : 'Degraded';
el.appendChild(b);
});
});
</script>
</body>
</html>import React, { useEffect } from 'react';
// CSS — optionally move to SystemStatusDashboardWidget.module.css
const css = `
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; background: #f8fafc; min-height: 100vh; padding: 24px 16px; }
.page { max-width: 600px; margin: 0 auto; display: flex; flex-direction: column; gap: 16px; }
.status-header { background: #fff; border: 1.5px solid #e2e8f0; border-radius: 14px; padding: 18px 20px; }
.header-top { display: flex; align-items: center; gap: 14px; }
.overall-dot { width: 14px; height: 14px; border-radius: 50%; flex-shrink: 0; }
.overall-dot.operational { background: #22c55e; box-shadow: 0 0 0 4px #dcfce7; }
.overall-dot.degraded { background: #f59e0b; box-shadow: 0 0 0 4px #fef9c3; }
.overall-dot.outage { background: #ef4444; box-shadow: 0 0 0 4px #fee2e2; }
.overall-title { font-size: 16px; font-weight: 800; color: #111827; margin-bottom: 2px; }
.overall-sub { font-size: 12px; color: #6b7280; }
.uptime-global { color: #16a34a; font-weight: 600; }
.services-list { background: #fff; border: 1.5px solid #e2e8f0; border-radius: 14px; overflow: hidden; }
.service-row { display: flex; align-items: center; gap: 12px; padding: 13px 18px; border-bottom: 1px solid #f3f4f6; }
.service-row:last-child { border-bottom: none; }
.svc-left { display: flex; align-items: center; gap: 10px; min-width: 150px; }
.svc-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.svc-dot.op { background: #22c55e; }
.svc-dot.deg { background: #f59e0b; }
.svc-dot.out { background: #ef4444; animation: pulse 1.2s infinite; }
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.4} }
.svc-name { font-size: 13px; font-weight: 600; color: #111827; }
.svc-latency { font-size: 10px; color: #9ca3af; }
.uptime-bars { flex: 1; display: flex; gap: 2px; align-items: flex-end; height: 24px; }
.uptime-bars .bar { flex: 1; border-radius: 2px; background: #22c55e; max-height: 24px; min-height: 8px; }
.uptime-bars .bar.out { background: #ef4444; }
.uptime-bars .bar.deg { background: #f59e0b; }
.svc-right { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; min-width: 88px; }
.svc-badge { font-size: 10px; font-weight: 700; padding: 2px 8px; border-radius: 20px; }
.op-badge { background: #dcfce7; color: #15803d; }
.deg-badge { background: #fef9c3; color: #a16207; }
.out-badge { background: #fee2e2; color: #dc2626; }
.svc-pct { font-size: 11px; font-weight: 600; color: #374151; }
.incident-box { background: #fff7ed; border: 1.5px solid #fed7aa; border-radius: 14px; padding: 14px 18px; }
.inc-title { display: flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 700; color: #c2410c; margin-bottom: 7px; }
.inc-body { font-size: 12px; color: #7c2d12; line-height: 1.6; margin-bottom: 6px; }
.inc-meta { font-size: 11px; color: #9a3412; }
.status-footer { display: flex; align-items: center; gap: 16px; padding: 4px 0; }
.legend-item { display: flex; align-items: center; gap: 5px; font-size: 11px; color: #6b7280; }
.leg-dot { width: 7px; height: 7px; border-radius: 50%; }
.leg-dot.op { background: #22c55e; }
.leg-dot.deg { background: #f59e0b; }
.leg-dot.out { background: #ef4444; }
.legend-right { margin-left: auto; }
`;
export default function SystemStatusDashboardWidget() {
// Auto-generated escape hatch: the original snippet's vanilla JS runs once
// after mount and queries the rendered DOM. For idiomatic React, lift this
// into state + handlers.
useEffect(() => {
const _listeners = [];
const _originalAddEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, listener, options) {
_listeners.push({ target: this, type, listener, options });
return _originalAddEventListener.call(this, type, listener, options);
};
const DATA = {
'bars-api': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.6,1],
'bars-web': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.7,1,1,1,1,1],
'bars-cdn': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.5,1,1,1,1,1,1,1,1,1,0.4,0.3,0.3,0.3],
'bars-db': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
'bars-auth':[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
'bars-wh': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.8,1,1,1,0.6,1,1,1,1,0.2,0.1,0,0,0,0]
};
Object.entries(DATA).forEach(([id, vals]) => {
const el = document.getElementById(id);
if (!el) return;
vals.forEach(v => {
const b = document.createElement('div');
b.className = 'bar' + (v === 0 ? ' out' : v < 0.5 ? ' deg' : '');
b.style.height = Math.max(8, Math.round(v * 24)) + 'px';
b.title = v === 1 ? 'Operational' : v === 0 ? 'Outage' : 'Degraded';
el.appendChild(b);
});
});
// Cleanup: restore addEventListener and remove all listeners
return () => {
EventTarget.prototype.addEventListener = _originalAddEventListener;
for (const { target, type, listener, options } of _listeners) {
target.removeEventListener(type, listener, options);
}
};
}, []);
return (
<>
<style>{css}</style>
<div className="page">
<div className="status-header">
<div className="header-top">
<div className="overall-dot operational"></div>
<div>
<h2 className="overall-title">All Systems Operational</h2>
<p className="overall-sub">Last checked: just now · <span className="uptime-global">99.97% uptime</span></p>
</div>
</div>
</div>
<div className="services-list">
<div className="service-row">
<div className="svc-left">
<span className="svc-dot op"></span>
<div>
<div className="svc-name">API Gateway</div>
<div className="svc-latency">42ms avg</div>
</div>
</div>
<div className="uptime-bars" id="bars-api"></div>
<div className="svc-right"><span className="svc-badge op-badge">Operational</span><span className="svc-pct">99.98%</span></div>
</div>
<div className="service-row">
<div className="svc-left">
<span className="svc-dot op"></span>
<div>
<div className="svc-name">Web Dashboard</div>
<div className="svc-latency">88ms avg</div>
</div>
</div>
<div className="uptime-bars" id="bars-web"></div>
<div className="svc-right"><span className="svc-badge op-badge">Operational</span><span className="svc-pct">99.95%</span></div>
</div>
<div className="service-row">
<div className="svc-left">
<span className="svc-dot deg"></span>
<div>
<div className="svc-name">CDN / Edge Network</div>
<div className="svc-latency">210ms avg</div>
</div>
</div>
<div className="uptime-bars" id="bars-cdn"></div>
<div className="svc-right"><span className="svc-badge deg-badge">Degraded</span><span className="svc-pct">98.40%</span></div>
</div>
<div className="service-row">
<div className="svc-left">
<span className="svc-dot op"></span>
<div>
<div className="svc-name">Database Cluster</div>
<div className="svc-latency">12ms avg</div>
</div>
</div>
<div className="uptime-bars" id="bars-db"></div>
<div className="svc-right"><span className="svc-badge op-badge">Operational</span><span className="svc-pct">100%</span></div>
</div>
<div className="service-row">
<div className="svc-left">
<span className="svc-dot op"></span>
<div>
<div className="svc-name">Auth Service</div>
<div className="svc-latency">31ms avg</div>
</div>
</div>
<div className="uptime-bars" id="bars-auth"></div>
<div className="svc-right"><span className="svc-badge op-badge">Operational</span><span className="svc-pct">99.99%</span></div>
</div>
<div className="service-row">
<div className="svc-left">
<span className="svc-dot out"></span>
<div>
<div className="svc-name">Webhooks</div>
<div className="svc-latency">— </div>
</div>
</div>
<div className="uptime-bars" id="bars-wh"></div>
<div className="svc-right"><span className="svc-badge out-badge">Outage</span><span className="svc-pct">95.10%</span></div>
</div>
</div>
<div className="incident-box">
<div className="inc-title">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
Active Incident
</div>
<p className="inc-body">Webhooks experiencing elevated failure rates. Engineering team investigating. CDN latency elevated in EU-West region.</p>
<div className="inc-meta">Started 14 min ago · Monitoring</div>
</div>
<div className="status-footer">
<span className="legend-item"><span className="leg-dot op"></span>Operational</span>
<span className="legend-item"><span className="leg-dot deg"></span>Degraded</span>
<span className="legend-item"><span className="leg-dot out"></span>Outage</span>
<span className="legend-item legend-right">90-day uptime</span>
</div>
</div>
</>
);
}import React, { useEffect } from 'react';
// Requires Tailwind CSS v3+ — https://tailwindcss.com/docs/installation
// Arbitrary value classes (e.g. bg-[#0f172a]) are valid Tailwind v3+
export default function SystemStatusDashboardWidget() {
// Auto-generated escape hatch: the original snippet's vanilla JS runs once
// after mount and queries the rendered DOM. For idiomatic React, lift this
// into state + handlers.
useEffect(() => {
const _listeners = [];
const _originalAddEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, listener, options) {
_listeners.push({ target: this, type, listener, options });
return _originalAddEventListener.call(this, type, listener, options);
};
const DATA = {
'bars-api': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.6,1],
'bars-web': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.7,1,1,1,1,1],
'bars-cdn': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.5,1,1,1,1,1,1,1,1,1,0.4,0.3,0.3,0.3],
'bars-db': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
'bars-auth':[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
'bars-wh': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.8,1,1,1,0.6,1,1,1,1,0.2,0.1,0,0,0,0]
};
Object.entries(DATA).forEach(([id, vals]) => {
const el = document.getElementById(id);
if (!el) return;
vals.forEach(v => {
const b = document.createElement('div');
b.className = 'bar' + (v === 0 ? ' out' : v < 0.5 ? ' deg' : '');
b.style.height = Math.max(8, Math.round(v * 24)) + 'px';
b.title = v === 1 ? 'Operational' : v === 0 ? 'Outage' : 'Degraded';
el.appendChild(b);
});
});
// Cleanup: restore addEventListener and remove all listeners
return () => {
EventTarget.prototype.addEventListener = _originalAddEventListener;
for (const { target, type, listener, options } of _listeners) {
target.removeEventListener(type, listener, options);
}
};
}, []);
return (
<>
<style>{`
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.4} }
* {
box-sizing: border-box; margin: 0; padding: 0;
}
body {
font-family: system-ui, sans-serif; background: #f8fafc; min-height: 100vh; padding: 24px 16px;
}
.overall-dot.operational {
background: #22c55e; box-shadow: 0 0 0 4px #dcfce7;
}
.overall-dot.degraded {
background: #f59e0b; box-shadow: 0 0 0 4px #fef9c3;
}
.overall-dot.outage {
background: #ef4444; box-shadow: 0 0 0 4px #fee2e2;
}
.service-row:last-child {
border-bottom: none;
}
.svc-dot.op {
background: #22c55e;
}
.svc-dot.deg {
background: #f59e0b;
}
.svc-dot.out {
background: #ef4444; animation: pulse 1.2s infinite;
}
.uptime-bars .bar {
flex: 1; border-radius: 2px; background: #22c55e; max-height: 24px; min-height: 8px;
}
.uptime-bars .bar.out {
background: #ef4444;
}
.uptime-bars .bar.deg {
background: #f59e0b;
}
.leg-dot.op {
background: #22c55e;
}
.leg-dot.deg {
background: #f59e0b;
}
.leg-dot.out {
background: #ef4444;
}
`}</style>
<div className="max-w-[600px] my-0 mx-auto flex flex-col gap-4">
<div className="bg-[#fff] border rounded-[14px] py-[18px] px-5">
<div className="flex items-center gap-3.5">
<div className="overall-dot w-3.5 h-3.5 rounded-full shrink-0 operational"></div>
<div>
<h2 className="text-base font-extrabold text-[#111827] mb-0.5">All Systems Operational</h2>
<p className="text-xs text-[#6b7280]">Last checked: just now · <span className="text-[#16a34a] font-semibold">99.97% uptime</span></p>
</div>
</div>
</div>
<div className="bg-[#fff] border rounded-[14px] overflow-hidden">
<div className="service-row flex items-center gap-3 py-[13px] px-[18px] border-b border-b-[#f3f4f6]">
<div className="flex items-center gap-2.5 min-w-[150px]">
<span className="svc-dot w-2 h-2 rounded-full shrink-0 op"></span>
<div>
<div className="text-[13px] font-semibold text-[#111827]">API Gateway</div>
<div className="text-xs text-[#9ca3af]">42ms avg</div>
</div>
</div>
<div className="uptime-bars flex-1 flex gap-0.5 items-end h-6" id="bars-api"></div>
<div className="flex flex-col items-end gap-[3px] min-w-[88px]"><span className="text-xs font-bold py-0.5 px-2 rounded-[20px] bg-[#dcfce7] text-[#15803d]">Operational</span><span className="text-[11px] font-semibold text-[#374151]">99.98%</span></div>
</div>
<div className="service-row flex items-center gap-3 py-[13px] px-[18px] border-b border-b-[#f3f4f6]">
<div className="flex items-center gap-2.5 min-w-[150px]">
<span className="svc-dot w-2 h-2 rounded-full shrink-0 op"></span>
<div>
<div className="text-[13px] font-semibold text-[#111827]">Web Dashboard</div>
<div className="text-xs text-[#9ca3af]">88ms avg</div>
</div>
</div>
<div className="uptime-bars flex-1 flex gap-0.5 items-end h-6" id="bars-web"></div>
<div className="flex flex-col items-end gap-[3px] min-w-[88px]"><span className="text-xs font-bold py-0.5 px-2 rounded-[20px] bg-[#dcfce7] text-[#15803d]">Operational</span><span className="text-[11px] font-semibold text-[#374151]">99.95%</span></div>
</div>
<div className="service-row flex items-center gap-3 py-[13px] px-[18px] border-b border-b-[#f3f4f6]">
<div className="flex items-center gap-2.5 min-w-[150px]">
<span className="svc-dot w-2 h-2 rounded-full shrink-0 deg"></span>
<div>
<div className="text-[13px] font-semibold text-[#111827]">CDN / Edge Network</div>
<div className="text-xs text-[#9ca3af]">210ms avg</div>
</div>
</div>
<div className="uptime-bars flex-1 flex gap-0.5 items-end h-6" id="bars-cdn"></div>
<div className="flex flex-col items-end gap-[3px] min-w-[88px]"><span className="text-xs font-bold py-0.5 px-2 rounded-[20px] bg-[#fef9c3] text-[#a16207]">Degraded</span><span className="text-[11px] font-semibold text-[#374151]">98.40%</span></div>
</div>
<div className="service-row flex items-center gap-3 py-[13px] px-[18px] border-b border-b-[#f3f4f6]">
<div className="flex items-center gap-2.5 min-w-[150px]">
<span className="svc-dot w-2 h-2 rounded-full shrink-0 op"></span>
<div>
<div className="text-[13px] font-semibold text-[#111827]">Database Cluster</div>
<div className="text-xs text-[#9ca3af]">12ms avg</div>
</div>
</div>
<div className="uptime-bars flex-1 flex gap-0.5 items-end h-6" id="bars-db"></div>
<div className="flex flex-col items-end gap-[3px] min-w-[88px]"><span className="text-xs font-bold py-0.5 px-2 rounded-[20px] bg-[#dcfce7] text-[#15803d]">Operational</span><span className="text-[11px] font-semibold text-[#374151]">100%</span></div>
</div>
<div className="service-row flex items-center gap-3 py-[13px] px-[18px] border-b border-b-[#f3f4f6]">
<div className="flex items-center gap-2.5 min-w-[150px]">
<span className="svc-dot w-2 h-2 rounded-full shrink-0 op"></span>
<div>
<div className="text-[13px] font-semibold text-[#111827]">Auth Service</div>
<div className="text-xs text-[#9ca3af]">31ms avg</div>
</div>
</div>
<div className="uptime-bars flex-1 flex gap-0.5 items-end h-6" id="bars-auth"></div>
<div className="flex flex-col items-end gap-[3px] min-w-[88px]"><span className="text-xs font-bold py-0.5 px-2 rounded-[20px] bg-[#dcfce7] text-[#15803d]">Operational</span><span className="text-[11px] font-semibold text-[#374151]">99.99%</span></div>
</div>
<div className="service-row flex items-center gap-3 py-[13px] px-[18px] border-b border-b-[#f3f4f6]">
<div className="flex items-center gap-2.5 min-w-[150px]">
<span className="svc-dot w-2 h-2 rounded-full shrink-0 out"></span>
<div>
<div className="text-[13px] font-semibold text-[#111827]">Webhooks</div>
<div className="text-xs text-[#9ca3af]">— </div>
</div>
</div>
<div className="uptime-bars flex-1 flex gap-0.5 items-end h-6" id="bars-wh"></div>
<div className="flex flex-col items-end gap-[3px] min-w-[88px]"><span className="text-xs font-bold py-0.5 px-2 rounded-[20px] bg-[#fee2e2] text-[#dc2626]">Outage</span><span className="text-[11px] font-semibold text-[#374151]">95.10%</span></div>
</div>
</div>
<div className="bg-[#fff7ed] border rounded-[14px] py-3.5 px-[18px]">
<div className="flex items-center gap-[7px] text-[13px] font-bold text-[#c2410c] mb-[7px]">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
Active Incident
</div>
<p className="text-xs text-[#7c2d12] leading-[1.6] mb-1.5">Webhooks experiencing elevated failure rates. Engineering team investigating. CDN latency elevated in EU-West region.</p>
<div className="text-[11px] text-[#9a3412]">Started 14 min ago · Monitoring</div>
</div>
<div className="flex items-center gap-4 py-1 px-0">
<span className="flex items-center gap-[5px] text-[11px] text-[#6b7280]"><span className="leg-dot w-[7px] h-[7px] rounded-full op"></span>Operational</span>
<span className="flex items-center gap-[5px] text-[11px] text-[#6b7280]"><span className="leg-dot w-[7px] h-[7px] rounded-full deg"></span>Degraded</span>
<span className="flex items-center gap-[5px] text-[11px] text-[#6b7280]"><span className="leg-dot w-[7px] h-[7px] rounded-full out"></span>Outage</span>
<span className="flex items-center gap-[5px] text-[11px] text-[#6b7280] ml-auto">90-day uptime</span>
</div>
</div>
</>
);
}<template>
<div class="page">
<div class="status-header">
<div class="header-top">
<div class="overall-dot operational"></div>
<div>
<h2 class="overall-title">All Systems Operational</h2>
<p class="overall-sub">Last checked: just now · <span class="uptime-global">99.97% uptime</span></p>
</div>
</div>
</div>
<div class="services-list">
<div class="service-row">
<div class="svc-left">
<span class="svc-dot op"></span>
<div>
<div class="svc-name">API Gateway</div>
<div class="svc-latency">42ms avg</div>
</div>
</div>
<div class="uptime-bars" id="bars-api"></div>
<div class="svc-right"><span class="svc-badge op-badge">Operational</span><span class="svc-pct">99.98%</span></div>
</div>
<div class="service-row">
<div class="svc-left">
<span class="svc-dot op"></span>
<div>
<div class="svc-name">Web Dashboard</div>
<div class="svc-latency">88ms avg</div>
</div>
</div>
<div class="uptime-bars" id="bars-web"></div>
<div class="svc-right"><span class="svc-badge op-badge">Operational</span><span class="svc-pct">99.95%</span></div>
</div>
<div class="service-row">
<div class="svc-left">
<span class="svc-dot deg"></span>
<div>
<div class="svc-name">CDN / Edge Network</div>
<div class="svc-latency">210ms avg</div>
</div>
</div>
<div class="uptime-bars" id="bars-cdn"></div>
<div class="svc-right"><span class="svc-badge deg-badge">Degraded</span><span class="svc-pct">98.40%</span></div>
</div>
<div class="service-row">
<div class="svc-left">
<span class="svc-dot op"></span>
<div>
<div class="svc-name">Database Cluster</div>
<div class="svc-latency">12ms avg</div>
</div>
</div>
<div class="uptime-bars" id="bars-db"></div>
<div class="svc-right"><span class="svc-badge op-badge">Operational</span><span class="svc-pct">100%</span></div>
</div>
<div class="service-row">
<div class="svc-left">
<span class="svc-dot op"></span>
<div>
<div class="svc-name">Auth Service</div>
<div class="svc-latency">31ms avg</div>
</div>
</div>
<div class="uptime-bars" id="bars-auth"></div>
<div class="svc-right"><span class="svc-badge op-badge">Operational</span><span class="svc-pct">99.99%</span></div>
</div>
<div class="service-row">
<div class="svc-left">
<span class="svc-dot out"></span>
<div>
<div class="svc-name">Webhooks</div>
<div class="svc-latency">— </div>
</div>
</div>
<div class="uptime-bars" id="bars-wh"></div>
<div class="svc-right"><span class="svc-badge out-badge">Outage</span><span class="svc-pct">95.10%</span></div>
</div>
</div>
<div class="incident-box">
<div class="inc-title">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
Active Incident
</div>
<p class="inc-body">Webhooks experiencing elevated failure rates. Engineering team investigating. CDN latency elevated in EU-West region.</p>
<div class="inc-meta">Started 14 min ago · Monitoring</div>
</div>
<div class="status-footer">
<span class="legend-item"><span class="leg-dot op"></span>Operational</span>
<span class="legend-item"><span class="leg-dot deg"></span>Degraded</span>
<span class="legend-item"><span class="leg-dot out"></span>Outage</span>
<span class="legend-item legend-right">90-day uptime</span>
</div>
</div>
</template>
<script setup>
import { onMounted } from 'vue';
const DATA = {
'bars-api': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.6,1],
'bars-web': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.7,1,1,1,1,1],
'bars-cdn': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.5,1,1,1,1,1,1,1,1,1,0.4,0.3,0.3,0.3],
'bars-db': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
'bars-auth':[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
'bars-wh': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.8,1,1,1,0.6,1,1,1,1,0.2,0.1,0,0,0,0]
};
onMounted(() => {
Object.entries(DATA).forEach(([id, vals]) => {
const el = document.getElementById(id);
if (!el) return;
vals.forEach(v => {
const b = document.createElement('div');
b.className = 'bar' + (v === 0 ? ' out' : v < 0.5 ? ' deg' : '');
b.style.height = Math.max(8, Math.round(v * 24)) + 'px';
b.title = v === 1 ? 'Operational' : v === 0 ? 'Outage' : 'Degraded';
el.appendChild(b);
});
});
});
</script>
<style scoped>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; background: #f8fafc; min-height: 100vh; padding: 24px 16px; }
.page { max-width: 600px; margin: 0 auto; display: flex; flex-direction: column; gap: 16px; }
.status-header { background: #fff; border: 1.5px solid #e2e8f0; border-radius: 14px; padding: 18px 20px; }
.header-top { display: flex; align-items: center; gap: 14px; }
.overall-dot { width: 14px; height: 14px; border-radius: 50%; flex-shrink: 0; }
.overall-dot.operational { background: #22c55e; box-shadow: 0 0 0 4px #dcfce7; }
.overall-dot.degraded { background: #f59e0b; box-shadow: 0 0 0 4px #fef9c3; }
.overall-dot.outage { background: #ef4444; box-shadow: 0 0 0 4px #fee2e2; }
.overall-title { font-size: 16px; font-weight: 800; color: #111827; margin-bottom: 2px; }
.overall-sub { font-size: 12px; color: #6b7280; }
.uptime-global { color: #16a34a; font-weight: 600; }
.services-list { background: #fff; border: 1.5px solid #e2e8f0; border-radius: 14px; overflow: hidden; }
.service-row { display: flex; align-items: center; gap: 12px; padding: 13px 18px; border-bottom: 1px solid #f3f4f6; }
.service-row:last-child { border-bottom: none; }
.svc-left { display: flex; align-items: center; gap: 10px; min-width: 150px; }
.svc-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.svc-dot.op { background: #22c55e; }
.svc-dot.deg { background: #f59e0b; }
.svc-dot.out { background: #ef4444; animation: pulse 1.2s infinite; }
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.4} }
.svc-name { font-size: 13px; font-weight: 600; color: #111827; }
.svc-latency { font-size: 10px; color: #9ca3af; }
.uptime-bars { flex: 1; display: flex; gap: 2px; align-items: flex-end; height: 24px; }
.uptime-bars .bar { flex: 1; border-radius: 2px; background: #22c55e; max-height: 24px; min-height: 8px; }
.uptime-bars .bar.out { background: #ef4444; }
.uptime-bars .bar.deg { background: #f59e0b; }
.svc-right { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; min-width: 88px; }
.svc-badge { font-size: 10px; font-weight: 700; padding: 2px 8px; border-radius: 20px; }
.op-badge { background: #dcfce7; color: #15803d; }
.deg-badge { background: #fef9c3; color: #a16207; }
.out-badge { background: #fee2e2; color: #dc2626; }
.svc-pct { font-size: 11px; font-weight: 600; color: #374151; }
.incident-box { background: #fff7ed; border: 1.5px solid #fed7aa; border-radius: 14px; padding: 14px 18px; }
.inc-title { display: flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 700; color: #c2410c; margin-bottom: 7px; }
.inc-body { font-size: 12px; color: #7c2d12; line-height: 1.6; margin-bottom: 6px; }
.inc-meta { font-size: 11px; color: #9a3412; }
.status-footer { display: flex; align-items: center; gap: 16px; padding: 4px 0; }
.legend-item { display: flex; align-items: center; gap: 5px; font-size: 11px; color: #6b7280; }
.leg-dot { width: 7px; height: 7px; border-radius: 50%; }
.leg-dot.op { background: #22c55e; }
.leg-dot.deg { background: #f59e0b; }
.leg-dot.out { background: #ef4444; }
.legend-right { margin-left: auto; }
</style>// @ts-nocheck
// Note: vanilla JS DOM manipulation is preserved as-is inside ngAfterViewInit().
// For idiomatic Angular, replace document.getElementById() with @ViewChild() refs
// and move state into component properties with two-way binding.
import { Component, AfterViewInit, ViewEncapsulation } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-system-status-dashboard-widget',
standalone: true,
imports: [CommonModule],
encapsulation: ViewEncapsulation.None,
template: `
<div class="page">
<div class="status-header">
<div class="header-top">
<div class="overall-dot operational"></div>
<div>
<h2 class="overall-title">All Systems Operational</h2>
<p class="overall-sub">Last checked: just now · <span class="uptime-global">99.97% uptime</span></p>
</div>
</div>
</div>
<div class="services-list">
<div class="service-row">
<div class="svc-left">
<span class="svc-dot op"></span>
<div>
<div class="svc-name">API Gateway</div>
<div class="svc-latency">42ms avg</div>
</div>
</div>
<div class="uptime-bars" id="bars-api"></div>
<div class="svc-right"><span class="svc-badge op-badge">Operational</span><span class="svc-pct">99.98%</span></div>
</div>
<div class="service-row">
<div class="svc-left">
<span class="svc-dot op"></span>
<div>
<div class="svc-name">Web Dashboard</div>
<div class="svc-latency">88ms avg</div>
</div>
</div>
<div class="uptime-bars" id="bars-web"></div>
<div class="svc-right"><span class="svc-badge op-badge">Operational</span><span class="svc-pct">99.95%</span></div>
</div>
<div class="service-row">
<div class="svc-left">
<span class="svc-dot deg"></span>
<div>
<div class="svc-name">CDN / Edge Network</div>
<div class="svc-latency">210ms avg</div>
</div>
</div>
<div class="uptime-bars" id="bars-cdn"></div>
<div class="svc-right"><span class="svc-badge deg-badge">Degraded</span><span class="svc-pct">98.40%</span></div>
</div>
<div class="service-row">
<div class="svc-left">
<span class="svc-dot op"></span>
<div>
<div class="svc-name">Database Cluster</div>
<div class="svc-latency">12ms avg</div>
</div>
</div>
<div class="uptime-bars" id="bars-db"></div>
<div class="svc-right"><span class="svc-badge op-badge">Operational</span><span class="svc-pct">100%</span></div>
</div>
<div class="service-row">
<div class="svc-left">
<span class="svc-dot op"></span>
<div>
<div class="svc-name">Auth Service</div>
<div class="svc-latency">31ms avg</div>
</div>
</div>
<div class="uptime-bars" id="bars-auth"></div>
<div class="svc-right"><span class="svc-badge op-badge">Operational</span><span class="svc-pct">99.99%</span></div>
</div>
<div class="service-row">
<div class="svc-left">
<span class="svc-dot out"></span>
<div>
<div class="svc-name">Webhooks</div>
<div class="svc-latency">— </div>
</div>
</div>
<div class="uptime-bars" id="bars-wh"></div>
<div class="svc-right"><span class="svc-badge out-badge">Outage</span><span class="svc-pct">95.10%</span></div>
</div>
</div>
<div class="incident-box">
<div class="inc-title">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
Active Incident
</div>
<p class="inc-body">Webhooks experiencing elevated failure rates. Engineering team investigating. CDN latency elevated in EU-West region.</p>
<div class="inc-meta">Started 14 min ago · Monitoring</div>
</div>
<div class="status-footer">
<span class="legend-item"><span class="leg-dot op"></span>Operational</span>
<span class="legend-item"><span class="leg-dot deg"></span>Degraded</span>
<span class="legend-item"><span class="leg-dot out"></span>Outage</span>
<span class="legend-item legend-right">90-day uptime</span>
</div>
</div>
`,
styles: [`
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; background: #f8fafc; min-height: 100vh; padding: 24px 16px; }
.page { max-width: 600px; margin: 0 auto; display: flex; flex-direction: column; gap: 16px; }
.status-header { background: #fff; border: 1.5px solid #e2e8f0; border-radius: 14px; padding: 18px 20px; }
.header-top { display: flex; align-items: center; gap: 14px; }
.overall-dot { width: 14px; height: 14px; border-radius: 50%; flex-shrink: 0; }
.overall-dot.operational { background: #22c55e; box-shadow: 0 0 0 4px #dcfce7; }
.overall-dot.degraded { background: #f59e0b; box-shadow: 0 0 0 4px #fef9c3; }
.overall-dot.outage { background: #ef4444; box-shadow: 0 0 0 4px #fee2e2; }
.overall-title { font-size: 16px; font-weight: 800; color: #111827; margin-bottom: 2px; }
.overall-sub { font-size: 12px; color: #6b7280; }
.uptime-global { color: #16a34a; font-weight: 600; }
.services-list { background: #fff; border: 1.5px solid #e2e8f0; border-radius: 14px; overflow: hidden; }
.service-row { display: flex; align-items: center; gap: 12px; padding: 13px 18px; border-bottom: 1px solid #f3f4f6; }
.service-row:last-child { border-bottom: none; }
.svc-left { display: flex; align-items: center; gap: 10px; min-width: 150px; }
.svc-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.svc-dot.op { background: #22c55e; }
.svc-dot.deg { background: #f59e0b; }
.svc-dot.out { background: #ef4444; animation: pulse 1.2s infinite; }
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.4} }
.svc-name { font-size: 13px; font-weight: 600; color: #111827; }
.svc-latency { font-size: 10px; color: #9ca3af; }
.uptime-bars { flex: 1; display: flex; gap: 2px; align-items: flex-end; height: 24px; }
.uptime-bars .bar { flex: 1; border-radius: 2px; background: #22c55e; max-height: 24px; min-height: 8px; }
.uptime-bars .bar.out { background: #ef4444; }
.uptime-bars .bar.deg { background: #f59e0b; }
.svc-right { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; min-width: 88px; }
.svc-badge { font-size: 10px; font-weight: 700; padding: 2px 8px; border-radius: 20px; }
.op-badge { background: #dcfce7; color: #15803d; }
.deg-badge { background: #fef9c3; color: #a16207; }
.out-badge { background: #fee2e2; color: #dc2626; }
.svc-pct { font-size: 11px; font-weight: 600; color: #374151; }
.incident-box { background: #fff7ed; border: 1.5px solid #fed7aa; border-radius: 14px; padding: 14px 18px; }
.inc-title { display: flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 700; color: #c2410c; margin-bottom: 7px; }
.inc-body { font-size: 12px; color: #7c2d12; line-height: 1.6; margin-bottom: 6px; }
.inc-meta { font-size: 11px; color: #9a3412; }
.status-footer { display: flex; align-items: center; gap: 16px; padding: 4px 0; }
.legend-item { display: flex; align-items: center; gap: 5px; font-size: 11px; color: #6b7280; }
.leg-dot { width: 7px; height: 7px; border-radius: 50%; }
.leg-dot.op { background: #22c55e; }
.leg-dot.deg { background: #f59e0b; }
.leg-dot.out { background: #ef4444; }
.legend-right { margin-left: auto; }
`]
})
export class SystemStatusDashboardWidgetComponent implements AfterViewInit {
ngAfterViewInit(): void {
const DATA = {
'bars-api': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.6,1],
'bars-web': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.7,1,1,1,1,1],
'bars-cdn': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.5,1,1,1,1,1,1,1,1,1,0.4,0.3,0.3,0.3],
'bars-db': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
'bars-auth':[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
'bars-wh': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.8,1,1,1,0.6,1,1,1,1,0.2,0.1,0,0,0,0]
};
Object.entries(DATA).forEach(([id, vals]) => {
const el = document.getElementById(id);
if (!el) return;
vals.forEach(v => {
const b = document.createElement('div');
b.className = 'bar' + (v === 0 ? ' out' : v < 0.5 ? ' deg' : '');
b.style.height = Math.max(8, Math.round(v * 24)) + 'px';
b.title = v === 1 ? 'Operational' : v === 0 ? 'Outage' : 'Degraded';
el.appendChild(b);
});
});
}
}