fix: choose buckets

This commit is contained in:
2026-04-09 02:23:11 +04:00
parent db9c63a096
commit 27d8630611
7 changed files with 60 additions and 23 deletions
+18 -15
View File
@@ -7,13 +7,6 @@ import sql from "./db";
export type Window = "24h" | "7d" | "30d" | "90d";
export type BucketType = "hourly" | "daily";
const WINDOW_TO_BUCKET: Record<Window, { bucket: BucketType; count: number }> = {
"24h": { bucket: "hourly", count: 24 },
"7d": { bucket: "daily", count: 7 },
"30d": { bucket: "daily", count: 30 },
"90d": { bucket: "daily", count: 90 }, // 90 daily bars; 90 rows per monitor, cached.
};
export interface StatusPageRow {
id: string;
account_id: string;
@@ -28,6 +21,8 @@ export interface StatusPageRow {
show_cert_expiry: boolean;
default_window: Window;
display_mode: "compact" | "expanded";
bar_frequency: BucketType;
bar_count: number;
custom_css: string | null;
footer_text: string | null;
og_image_url: string | null;
@@ -153,7 +148,13 @@ export async function loadGroups(pageId: string): Promise<GroupRow[]> {
`;
}
export async function loadMonitors(pageId: string, window: Window, pageDisplayMode: "compact" | "expanded" = "expanded"): Promise<MonitorRow[]> {
export async function loadMonitors(
pageId: string,
window: Window,
pageDisplayMode: "compact" | "expanded" = "expanded",
barFrequency: BucketType = "daily",
barCount: number = 90,
): Promise<MonitorRow[]> {
// Step 1: page → monitors with display overrides + group + position.
const monitorRows = await sql<any[]>`
SELECT
@@ -188,11 +189,13 @@ export async function loadMonitors(pageId: string, window: Window, pageDisplayMo
});
}
// Step 3: uptime rollup buckets covering the requested window. We keep
// region in the result so JS can pick the fastest region per monitor and
// emit per-bucket latency from just that region (status pages are
// customer-facing, we show our best foot forward).
const { bucket, count } = WINDOW_TO_BUCKET[window];
// Step 3: uptime rollup buckets covering the requested window. The bar
// frequency + count are admin-controlled per page (independent of the
// multi-window uptime cells). We keep region in the result so JS can pick
// the fastest region per monitor and emit per-bucket latency from just
// that region (status pages are customer-facing — show the best line).
const bucket: BucketType = barFrequency;
const count = Math.max(1, Math.min(180, barCount));
const truncUnit = bucket === "hourly" ? "hour" : "day";
const intervalLiteral = `${count} ${truncUnit}s`;
let rollupRows = await sql<any[]>`
@@ -432,7 +435,7 @@ export async function loadMonitorDetail(slug: string, monitorId: string, window?
const win = (window ?? page.default_window) as Window;
// Reuse the bulk loader with a single-monitor list — keeps the bucket/state
// logic in one place. Cheap because we're querying for one ID.
const monitors = await loadMonitors(page.id, win, page.display_mode);
const monitors = await loadMonitors(page.id, win, page.display_mode, page.bar_frequency, page.bar_count);
const m = monitors.find((x) => x.id === monitorId);
if (!m) return null;
@@ -493,7 +496,7 @@ export async function loadPagePayload(slug: string, window?: Window): Promise<Pa
const win = (window ?? page.default_window) as Window;
const [groups, monitors, incidents] = await Promise.all([
loadGroups(page.id),
loadMonitors(page.id, win, page.display_mode),
loadMonitors(page.id, win, page.display_mode, page.bar_frequency, page.bar_count),
loadIncidents(page.id),
]);
const { password_hash, ...publicPage } = page;
+3 -3
View File
@@ -5,7 +5,7 @@
// class on click. Reads its config from window.PINGQL_PAGE.
(function () {
var cfg = window.PINGQL_PAGE || {};
var defaultWindow = cfg.default_window || "24h";
var barFrequency = cfg.bar_frequency || "daily";
// ── Click to expand/collapse ──────────────────────────────────────────
var rows = document.querySelectorAll(".monitor .monitor-row");
@@ -23,13 +23,13 @@
var tooltip = document.getElementById("bar-tooltip");
if (!tooltip) return;
var bucketSpanMs = (defaultWindow === "24h") ? 3600 * 1000 : 86400 * 1000;
var bucketSpanMs = (barFrequency === "hourly") ? 3600 * 1000 : 86400 * 1000;
function fmtBucketRange(startIso) {
var start = new Date(startIso);
var end = new Date(start.getTime() + bucketSpanMs);
var dateOpts = { month: "short", day: "numeric" };
var timeOpts = { hour: "2-digit", minute: "2-digit" };
if (defaultWindow === "24h") {
if (barFrequency === "hourly") {
return start.toLocaleDateString(undefined, dateOpts) + ", " +
start.toLocaleTimeString(undefined, timeOpts) + " — " +
end.toLocaleTimeString(undefined, timeOpts);
+4 -5
View File
@@ -257,10 +257,9 @@
// 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.default_window === '24h' ? 'Last 24 hours'
: page.default_window === '7d' ? 'Last 7 days'
: page.default_window === '30d' ? 'Last 30 days'
: 'Last 90 days';
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' });
@@ -366,7 +365,7 @@
</main>
<div id="bar-tooltip" role="tooltip"></div>
<script>window.PINGQL_PAGE = <%~ JSON.stringify({ slug: page.slug, default_window: page.default_window, show_response_time: !!page.show_response_time }) %>;</script>
<script>window.PINGQL_PAGE = <%~ JSON.stringify({ slug: page.slug, default_window: page.default_window, bar_frequency: page.bar_frequency, show_response_time: !!page.show_response_time }) %>;</script>
<script src="/_static/expand.js?v=<%= it.expandJsHash %>" defer></script>
<% if (page.auto_refresh_s > 0) { %>