feat: status page authoring UI

This commit is contained in:
2026-08-25 08:32:43 +00:00
parent bf10023f35
commit 1452928b75
4 changed files with 1152 additions and 0 deletions
+124
View File
@@ -111,6 +111,67 @@ export interface Rollup {
sum_latency: number;
}
// ---------------------------------------------------------------------------
// Status page authoring types. These mirror server/internal/models/statuspage.go
// field for field -- that Go file is the contract. The public shapes
// (PublicDay, PublicComponent, PublicSection, PublicIncident, StatusSnapshot)
// live further down this file, added by the public status page task; this
// block must not redeclare them.
// ---------------------------------------------------------------------------
export type StatusPageKind = "incident" | "maintenance";
export type StatusImpact = "none" | "minor" | "major" | "critical";
export interface StatusPageEntry {
monitor_id: string;
display_name?: string;
}
export interface StatusPageSection {
name: string;
entries: StatusPageEntry[];
}
export interface StatusPageBanner {
enabled: boolean;
level?: string;
text?: string;
}
export interface StatusPage {
page_id: string;
title: string;
description?: string;
logo_url?: string;
published: boolean;
banner: StatusPageBanner;
sections: StatusPageSection[];
created_at: string;
updated_at: string;
}
export interface StatusIncidentUpdate {
at: string;
status: string;
body: string;
author?: string;
}
export interface StatusIncident {
incident_id: string;
page_ids: string[];
kind: StatusPageKind;
title: string;
impact: StatusImpact;
affected_monitors?: string[];
status: string;
scheduled_start?: string;
scheduled_end?: string;
updates: StatusIncidentUpdate[];
started_at: string;
resolved_at?: string;
}
export type ChannelType = "webhook" | "smtp" | "discord" | "slack" | "telegram";
/**
@@ -682,6 +743,69 @@ export const api = {
return request<MonitorSample[]>(`/monitors/${monitorId}/samples?minutes=${minutes}`);
},
listStatusPages(): Promise<StatusPage[]> {
return request<StatusPage[]>("/status-pages");
},
getStatusPage(pageId: string): Promise<StatusPage> {
return request<StatusPage>(`/status-pages/${pageId}`);
},
createStatusPage(input: Partial<StatusPage>): Promise<StatusPage> {
return request<StatusPage>("/status-pages", { method: "POST", body: JSON.stringify(input) });
},
updateStatusPage(pageId: string, input: Partial<StatusPage>): Promise<StatusPage> {
return request<StatusPage>(`/status-pages/${pageId}`, {
method: "PUT",
body: JSON.stringify(input),
});
},
deleteStatusPage(pageId: string): Promise<void> {
return request<void>(`/status-pages/${pageId}`, { method: "DELETE" });
},
listStatusIncidents(pageId: string): Promise<StatusIncident[]> {
return request<StatusIncident[]>(`/status-pages/${pageId}/incidents`);
},
createStatusIncident(pageId: string, input: Partial<StatusIncident>): Promise<StatusIncident> {
return request<StatusIncident>(`/status-pages/${pageId}/incidents`, {
method: "POST",
body: JSON.stringify(input),
});
},
updateStatusIncident(
pageId: string,
incidentId: string,
input: Partial<StatusIncident>,
): Promise<StatusIncident> {
return request<StatusIncident>(`/status-pages/${pageId}/incidents/${incidentId}`, {
method: "PUT",
body: JSON.stringify(input),
});
},
deleteStatusIncident(pageId: string, incidentId: string): Promise<void> {
return request<void>(`/status-pages/${pageId}/incidents/${incidentId}`, {
method: "DELETE",
});
},
postStatusIncidentUpdate(
pageId: string,
incidentId: string,
status: string,
body: string,
): Promise<StatusIncident> {
return request<StatusIncident>(`/status-pages/${pageId}/incidents/${incidentId}/updates`, {
method: "POST",
body: JSON.stringify({ status, body }),
});
},
listChannels(): Promise<NotificationChannel[]> {
return request<NotificationChannel[]>("/channels");
},