%
const page = it.page;
const monitors = it.monitors;
const groups = it.groups;
const incidents = it.incidents;
const themeClass = page.theme === 'dark' ? 'dark' : page.theme === 'light' ? 'light' : '';
// Group monitors. group_id null = "ungrouped".
const grouped = {};
for (const m of monitors) {
const key = m.group_id || '';
if (!grouped[key]) grouped[key] = [];
grouped[key].push(m);
}
const groupOrder = [...groups.map(g => g.id), ''];
function fmtPct(p) {
if (p == null) return '-';
// Only show "100%" when the value is *exactly* 100. Anything below - even
// 99.9999% - must show 2 decimals so visitors can see there was downtime.
// Truncate (floor) rather than round, otherwise 99.9999 would render as
// "100.00" and silently swallow the downtime.
if (p >= 100) return '100%';
return (Math.floor(p * 100) / 100).toFixed(2) + '%';
}
function statusLabel(s) {
if (s === 'up') return 'Operational';
if (s === 'down') return 'Down';
if (s === 'paused') return 'Under maintenance';
return 'Unknown';
}
function statusColor(s) {
if (s === 'up') return 'var(--bar-up)';
if (s === 'down') return 'var(--bar-down)';
if (s === 'paused') return 'var(--bar-paused)';
return 'var(--muted)';
}
function bucketColor(b) {
if (!b || b.total === 0) return 'var(--bar-empty)';
if (b.up === b.total) return 'var(--bar-up)';
if (b.up === 0) return 'var(--bar-down)';
return 'var(--bar-partial)';
}
function uptimeBand(p) {
if (p == null) return 'empty';
if (p >= 97) return 'good';
if (p >= 87) return 'warn';
return 'bad';
}
function fmtUptime(p) {
if (p == null) return '-';
// Only "100%" if the monitor was up for every single check in the window.
// Truncate (not round) below that so 99.9999% never displays as "100.00".
if (p >= 100) return '100%';
return (Math.floor(p * 100) / 100).toFixed(2) + '%';
}
// Overall status: down if any monitor is down, degraded if any partial, else up.
// Paused monitors are operator-declared maintenance - they don't count
// toward "down" or "degraded", but we surface a small note in the banner
// when at least one is in maintenance so visitors aren't confused.
let paused_count = 0;
let down_count = 0;
let active_count = 0;
let has_degraded = false;
for (const m of monitors) {
if (m.current_state === 'paused') { paused_count++; continue; }
active_count++;
const partial = m.region_states.some(r => r.state === 'down') && m.region_states.some(r => r.state === 'up');
if (m.current_state === 'down') down_count++;
else if (partial) has_degraded = true;
}
const overall = down_count === 0 && !has_degraded ? 'up'
: active_count > 0 && down_count === active_count ? 'down'
: 'degraded';
let overallText = overall === 'up' ? 'All systems operational'
: overall === 'down' ? 'Major outage in progress'
: 'Partial outage';
if (paused_count > 0) {
overallText += ' - ' + paused_count + (paused_count === 1 ? ' service' : ' services') + ' under maintenance';
}
const overallBg = overall === 'up' ? 'rgba(16,185,129,0.1)'
: overall === 'degraded' ? 'rgba(245,158,11,0.1)'
: 'rgba(239,68,68,0.1)';
const overallBorder = overall === 'up' ? 'rgba(16,185,129,0.25)'
: overall === 'degraded' ? 'rgba(245,158,11,0.25)'
: 'rgba(239,68,68,0.25)';
const overallFg = overall === 'up' ? 'var(--bar-up)'
: overall === 'degraded' ? 'var(--bar-partial)'
: 'var(--bar-down)';
const dotColor = overall === 'up' ? '#10b981'
: overall === 'degraded' ? '#f59e0b'
: '#ef4444';
const dotGlow = overall === 'up' ? 'rgba(16,185,129,0.4)'
: overall === 'degraded' ? 'rgba(245,158,11,0.4)'
: 'rgba(239,68,68,0.4)';
%>
<%= page.title %>
<% if (page.description) { %> <% } %>
<% if (!page.index_search) { %> <% } %>
<% if (page.description) { %> <% } %>
<% if (page.og_image_url) { %> <% } %>
<% if (page.custom_css) { %><% } %>
<% if (page.analytics_html) { %><%~ page.analytics_html %><% } %>
<% if (page.description) { %><%= page.description %>
<% } %>
<%= overallText %>
<% if (incidents.active.length > 0) { %>
<% incidents.active.forEach(function(i) { %>
<%= i.title %>
<%= i.status %>
Started <%= fmtTimestamp(i.started_at) %>
<% if (i.resolved_at) { %> ยท Resolved <%= fmtTimestamp(i.resolved_at) %><% } %>
<% if (i.updates && i.updates.length > 0) { %>
<% i.updates.forEach(function(u) { %>
<%= u.status %>
<%= fmtTimestamp(u.created_at) %>
<%~ u.body_html %>
<% }); %>
<% } %>
<% }); %>
<% } %>
<%
// Per-monitor mode now lives on each MonitorRow.display_mode (already
// resolved against the page-level fallback by the data layer). The
// page-level isCompact is kept only as a hint for whether to emit the
// expand JS at all.
const anyCompact = monitors.some(m => m.display_mode === 'compact');
const windowLabel = page.bar_frequency === 'hourly'
? ('Last ' + page.bar_count + ' hour' + (page.bar_count === 1 ? '' : 's'))
: ('Last ' + page.bar_count + ' day' + (page.bar_count === 1 ? '' : 's'));
function fmtTimestamp(iso) {
const d = new Date(iso);
return d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' });
}
%>
<% groupOrder.forEach(function(gid, gi) {
const list = grouped[gid];
if (!list || list.length === 0) return;
const groupName = gid ? (groups.find(g => g.id === gid)?.name || '') : '';
// Aggregate status for the group header
const activeInGroup = list.filter(m => m.current_state !== 'paused');
const downInGroup = activeInGroup.filter(m => m.current_state === 'down').length;
const groupStatus = activeInGroup.length === 0 ? 'unknown' : downInGroup === activeInGroup.length ? 'down' : downInGroup > 0 ? 'degraded' : 'up';
const groupStatusLabel = groupStatus === 'up' ? 'Operational' : groupStatus === 'degraded' ? 'Degraded' : groupStatus === 'down' ? 'Down' : '';
const groupStatusColor = groupStatus === 'up' ? 'var(--bar-up)' : groupStatus === 'degraded' ? 'var(--bar-partial)' : groupStatus === 'down' ? 'var(--bar-down)' : 'var(--muted)';
%>
<% if (groupName) {
// Aggregate buckets across all monitors in the group (weighted average)
const aggBuckets = [];
const firstWithBuckets = list.find(m => m.buckets && m.buckets.length > 0);
if (firstWithBuckets) {
for (let bi = 0; bi < firstWithBuckets.buckets.length; bi++) {
let t = 0, u = 0, latSum = 0, latN = 0;
for (const m of list) {
if (!m.buckets || !m.buckets[bi]) continue;
t += m.buckets[bi].total;
u += m.buckets[bi].up;
if (m.buckets[bi].avg_latency != null) { latSum += m.buckets[bi].avg_latency * m.buckets[bi].total; latN += m.buckets[bi].total; }
}
aggBuckets.push({ start: firstWithBuckets.buckets[bi].start, total: t, up: u, avg_latency: latN > 0 ? Math.round(latSum / latN) : null });
}
}
const aggTotal = aggBuckets.reduce((a, b) => a + b.total, 0);
const aggUp = aggBuckets.reduce((a, b) => a + b.up, 0);
const aggPct = aggTotal > 0 ? (100 * aggUp / aggTotal) : null;
%>
<% aggBuckets.forEach(function(b) { %>
data-latency="<%= b.avg_latency %>"<% } %>>
<% }); %>
<% } %>
<% list.forEach(function(m) {
const buckets = m.buckets || [];
const hasData = buckets.some(b => b.total > 0);
const u = m.uptime || { d24: null, d7: null, d30: null, d90: null };
// Every monitor renders with the same DOM. display_mode just sets
// whether the detail panel starts expanded or collapsed.
const startsOpen = m.display_mode !== 'compact';
%>
>
<%= m.display_name %>
<% buckets.forEach(function(b) { %>
data-latency="<%= b.avg_latency %>"<% } %>>
<% }); %>
<%= windowLabel %>
<%= hasData ? 'uptime over window' : 'awaiting data' %>
24h
<%= fmtUptime(u.d24) %>
30d
<%= fmtUptime(u.d30) %>
90d
<%= fmtUptime(u.d90) %>
<% }); %>
<% if (groupName) { %>
<% } %>
<% }); %>
<% if (incidents.recent.length > 0) { %>
<%
// Group past incidents by their started_at date (Y-M-D in local time).
// Atlassian-style: each date is its own section, incidents listed below.
var pastByDate = {};
var pastOrder = [];
for (var pi = 0; pi < incidents.recent.length; pi++) {
var inc = incidents.recent[pi];
var d = new Date(inc.started_at);
var key = d.getFullYear() + '-' + (d.getMonth()+1) + '-' + d.getDate();
if (!pastByDate[key]) {
pastByDate[key] = { date: d, items: [] };
pastOrder.push(key);
}
pastByDate[key].items.push(inc);
}
%>
Past incidents
<% pastOrder.forEach(function(k) {
var day = pastByDate[k];
var dateLabel = day.date.toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' });
%>
<% day.items.forEach(function(i) { %>
<%= i.title %>
<% if (i.updates && i.updates.length > 0) { %>
<% i.updates.forEach(function(u) { %>
<%= u.status %>
- <%~ u.body_html %>
<%= fmtTimestamp(u.created_at) %>
<% }); %>
<% } %>
<% }); %>
<% }); %>
<% } %>
<% if (page.footer_text) { %><%= page.footer_text %>
<% } %>
<% if (page.show_powered_by) { %><% } %>
<% if (page.auto_refresh_s > 0) { %>
<% } %>