feat(web): heartbeat monitor form, ping URL panel and token rotation

This commit is contained in:
2026-09-17 08:33:29 +00:00
parent 17ed0192c1
commit 42358f57cb
7 changed files with 227 additions and 58 deletions
+27 -1
View File
@@ -45,9 +45,13 @@ export interface Server {
tags?: Record<string, string>;
}
export type MonitorType = "http" | "tcp" | "icmp" | "tls";
export type MonitorType = "http" | "tcp" | "icmp" | "tls" | "heartbeat" | "metric";
export type MonitorStatus = "up" | "down" | "pending";
export type MetricKind =
| "disk_pct" | "disk_free_gb" | "mem_pct" | "load_per_core"
| "unit_failed" | "container_unhealthy" | "reboot_pending_days" | "agent_offline_min";
export interface MonitorTarget {
url?: string;
host?: string;
@@ -57,6 +61,12 @@ export interface MonitorTarget {
keyword?: string;
tls_warn_days?: number;
insecure?: boolean;
period_sec?: number;
grace_sec?: number;
selector?: Record<string, string>;
metric?: MetricKind;
threshold?: number;
mount?: string;
}
export interface MonitorState {
@@ -66,6 +76,8 @@ export interface MonitorState {
message?: string;
cert_expiry_at?: string;
fails: number;
last_ping_at?: string;
started_at?: string;
}
export interface Monitor {
@@ -82,6 +94,9 @@ export interface Monitor {
channel_ids?: string[];
state: MonitorState;
created_at: string;
for_sec?: number;
/** Plaintext heartbeat ping token. Only ever present on the create response. */
heartbeat_token?: string;
}
export interface MonitorInput {
@@ -94,6 +109,7 @@ export interface MonitorInput {
retries: number;
enabled: boolean;
channel_ids?: string[];
for_sec?: number;
}
export interface Incident {
@@ -102,6 +118,7 @@ export interface Incident {
started_at: string;
resolved_at?: string;
cause?: string;
server_id?: string;
}
/** One check result. Kept for 48 hours, which is what the sub-hour views read. */
@@ -1026,6 +1043,10 @@ export const api = {
return request<MonitorSample[]>(`/monitors/${monitorId}/samples?minutes=${minutes}`);
},
rotateHeartbeatToken(monitorId: string) {
return request<{ heartbeat_token: string }>(`/monitors/${monitorId}/rotate-token`, { method: "POST" });
},
listStatusPages(): Promise<StatusPage[]> {
return request<StatusPage[]>("/status-pages");
},
@@ -1441,6 +1462,11 @@ export const api = {
},
};
/** The ping URL a job calls. Same origin as the app: /public is routed to the server everywhere. */
export function heartbeatUrl(token: string): string {
return `${window.location.origin}/public/hb/${token}`;
}
export type LicenseState = "valid" | "expired" | "invalid";
export interface LicenseInfo {