status page usage

This commit is contained in:
Ian Gulliver
2026-10-16 10:47:53 -07:00
parent a800ac4f56
commit 919e1f8002
7 changed files with 106 additions and 10 deletions
+19 -1
View File
@@ -148,9 +148,27 @@ function rateLimitCard(vendor, info) {
const tone = statusText === "allowed" ? "ok" : statusText === "rejected" ? "danger" : "warn";
const windows = (unifiedWindows ?? {});
return h("div", { class: "card rate-limit" }, h("header", {}, h("span", { class: "vendor" }, vendor), h("span", { class: `rl-status ${tone}` }, statusText), rateLimitType !== undefined && h("span", {}, String(rateLimitType)), typeof resetsAt === "number" && h("span", { class: "resets" }, "resets ", resetText(resetsAt))), Object.keys(windows).length > 0 &&
h("table", { class: "rl-windows" }, h("tr", {}, h("th", {}, "Window"), h("th", {}, "Used"), h("th", {}, "Resets")), ...Object.entries(windows).map(([name, w]) => h("tr", {}, h("td", {}, name), h("td", { class: utilizationClass(w.utilization) }, w.utilization === undefined ? "—" : `${Math.round(w.utilization * 100)}%`), h("td", {}, w.resetsAt === undefined ? "—" : resetText(w.resetsAt))))), Object.keys(rest).length > 0 &&
h("table", { class: "rl-windows" }, h("tr", {}, h("th", {}, "Window"), h("th", {}, "Used"), h("th", {}, "Elapsed"), h("th", { class: "rl-pace-col" }, "Pace"), h("th", {}, "Resets")), ...Object.entries(windows).map(([name, w]) => {
const elapsed = elapsedFraction(w);
return h("tr", {}, h("td", {}, name), h("td", { class: utilizationClass(w.utilization) }, w.utilization === undefined ? "—" : `${Math.round(w.utilization * 100)}%`), h("td", {}, elapsed === undefined ? "—" : `${Math.round(elapsed * 100)}%`), h("td", { class: "rl-pace-col" }, paceBar(w.utilization, elapsed)), h("td", {}, w.resetsAt === undefined ? "—" : resetText(w.resetsAt)));
})), Object.keys(rest).length > 0 &&
h("dl", { class: "kv" }, ...Object.entries(rest).flatMap(([k, v]) => [h("dt", {}, k), h("dd", {}, typeof v === "object" ? JSON.stringify(v) : String(v))])));
}
function elapsedFraction(w) {
if (w.resetsAt === undefined || w.windowMins === undefined) {
return undefined;
}
const remaining = w.resetsAt * 1000 - Date.now();
return Math.min(1, Math.max(0, 1 - remaining / (w.windowMins * 60000)));
}
function paceBar(used, elapsed) {
if (used === undefined || elapsed === undefined) {
return "—";
}
const diff = Math.round((used - elapsed) * 100);
const title = diff > 0 ? `${diff} points ahead of an even pace` : diff < 0 ? `${-diff} points behind an even pace` : "on an even pace";
return h("div", { class: `rl-pace ${used > elapsed ? "ahead" : "behind"}`, title }, h("div", { class: "rl-pace-used", style: `width: ${Math.min(1, used) * 100}%` }), h("div", { class: "rl-pace-now", style: `left: ${elapsed * 100}%` }));
}
function utilizationClass(u) {
if (u === undefined) {
return "";
+1 -1
View File
File diff suppressed because one or more lines are too long
+33 -6
View File
@@ -215,7 +215,7 @@ function rateLimitCard(vendor: string, info: Record<string, unknown>): HTMLEleme
const { status, rateLimitType, resetsAt, unifiedWindows, ...rest } = info;
const statusText = String(status ?? "unknown");
const tone = statusText === "allowed" ? "ok" : statusText === "rejected" ? "danger" : "warn";
const windows = (unifiedWindows ?? {}) as Record<string, { utilization?: number; resetsAt?: number }>;
const windows = (unifiedWindows ?? {}) as Record<string, RateWindow>;
return h(
"div",
@@ -232,16 +232,19 @@ function rateLimitCard(vendor: string, info: Record<string, unknown>): HTMLEleme
h(
"table",
{ class: "rl-windows" },
h("tr", {}, h("th", {}, "Window"), h("th", {}, "Used"), h("th", {}, "Resets")),
...Object.entries(windows).map(([name, w]) =>
h(
h("tr", {}, h("th", {}, "Window"), h("th", {}, "Used"), h("th", {}, "Elapsed"), h("th", { class: "rl-pace-col" }, "Pace"), h("th", {}, "Resets")),
...Object.entries(windows).map(([name, w]) => {
const elapsed = elapsedFraction(w);
return h(
"tr",
{},
h("td", {}, name),
h("td", { class: utilizationClass(w.utilization) }, w.utilization === undefined ? "—" : `${Math.round(w.utilization * 100)}%`),
h("td", {}, elapsed === undefined ? "—" : `${Math.round(elapsed * 100)}%`),
h("td", { class: "rl-pace-col" }, paceBar(w.utilization, elapsed)),
h("td", {}, w.resetsAt === undefined ? "—" : resetText(w.resetsAt)),
),
),
);
}),
),
Object.keys(rest).length > 0 &&
h(
@@ -252,6 +255,30 @@ function rateLimitCard(vendor: string, info: Record<string, unknown>): HTMLEleme
);
}
type RateWindow = { utilization?: number; resetsAt?: number; windowMins?: number };
function elapsedFraction(w: RateWindow): number | undefined {
if (w.resetsAt === undefined || w.windowMins === undefined) {
return undefined;
}
const remaining = w.resetsAt * 1000 - Date.now();
return Math.min(1, Math.max(0, 1 - remaining / (w.windowMins * 60000)));
}
function paceBar(used: number | undefined, elapsed: number | undefined): HTMLElement | string {
if (used === undefined || elapsed === undefined) {
return "—";
}
const diff = Math.round((used - elapsed) * 100);
const title = diff > 0 ? `${diff} points ahead of an even pace` : diff < 0 ? `${-diff} points behind an even pace` : "on an even pace";
return h(
"div",
{ class: `rl-pace ${used > elapsed ? "ahead" : "behind"}`, title },
h("div", { class: "rl-pace-used", style: `width: ${Math.min(1, used) * 100}%` }),
h("div", { class: "rl-pace-now", style: `left: ${elapsed * 100}%` }),
);
}
function utilizationClass(u: number | undefined): string {
if (u === undefined) {
return "";
+30
View File
@@ -2282,6 +2282,36 @@ button.danger-primary {
border-bottom: 1px solid var(--border);
}
.rl-windows .rl-pace-col {
width: 40%;
}
.rl-pace {
position: relative;
height: 10px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 2px;
}
.rl-pace-used {
height: 100%;
background: color-mix(in srgb, var(--ok) 55%, var(--raised));
}
.rl-pace.ahead .rl-pace-used {
background: color-mix(in srgb, var(--warn) 55%, var(--raised));
}
.rl-pace-now {
position: absolute;
top: -3px;
bottom: -3px;
width: 2px;
margin-left: -1px;
background: var(--text);
}
.problems {
list-style: none;
margin: 0;