249894d8e1
- Filters status/severity/hostname; /problems/:id with Ack/Resolve and timeline - Dashboard drill-down to open problems Co-authored-by: Cursor <cursoragent@cursor.com>
150 lines
3.4 KiB
TypeScript
150 lines
3.4 KiB
TypeScript
const TOKEN_KEY = "sac_token";
|
|
|
|
export function getToken(): string | null {
|
|
return localStorage.getItem(TOKEN_KEY);
|
|
}
|
|
|
|
export function setToken(token: string): void {
|
|
localStorage.setItem(TOKEN_KEY, token);
|
|
}
|
|
|
|
export function clearToken(): void {
|
|
localStorage.removeItem(TOKEN_KEY);
|
|
}
|
|
|
|
export async function apiFetch<T>(path: string, init: RequestInit = {}): Promise<T> {
|
|
const headers = new Headers(init.headers);
|
|
if (!headers.has("Content-Type") && init.body) {
|
|
headers.set("Content-Type", "application/json");
|
|
}
|
|
const token = getToken();
|
|
if (token) {
|
|
headers.set("Authorization", `Bearer ${token}`);
|
|
}
|
|
const res = await fetch(path, { ...init, headers });
|
|
if (res.status === 401) {
|
|
clearToken();
|
|
window.location.href = "/login";
|
|
throw new Error("Unauthorized");
|
|
}
|
|
if (!res.ok) {
|
|
const text = await res.text();
|
|
throw new Error(text || res.statusText);
|
|
}
|
|
return res.json() as Promise<T>;
|
|
}
|
|
|
|
export interface TokenResponse {
|
|
access_token: string;
|
|
token_type: string;
|
|
}
|
|
|
|
export interface EventSummary {
|
|
id: number;
|
|
event_id: string;
|
|
host_id: number;
|
|
hostname: string;
|
|
occurred_at: string;
|
|
received_at: string;
|
|
category: string;
|
|
type: string;
|
|
severity: string;
|
|
title: string;
|
|
summary: string;
|
|
}
|
|
|
|
export interface EventListResponse {
|
|
items: EventSummary[];
|
|
total: number;
|
|
page: number;
|
|
page_size: number;
|
|
}
|
|
|
|
export interface EventDetail extends EventSummary {
|
|
details: Record<string, unknown> | null;
|
|
raw: Record<string, unknown> | null;
|
|
payload: Record<string, unknown>;
|
|
}
|
|
|
|
export interface HostSummary {
|
|
id: number;
|
|
hostname: string;
|
|
display_name: string | null;
|
|
os_family: string;
|
|
product: string;
|
|
product_version: string | null;
|
|
ipv4: string | null;
|
|
last_seen_at: string;
|
|
event_count: number | null;
|
|
last_heartbeat_at: string | null;
|
|
last_daily_report_at: string | null;
|
|
agent_status: "online" | "stale" | "unknown";
|
|
}
|
|
|
|
export interface HostListResponse {
|
|
items: HostSummary[];
|
|
total: number;
|
|
page: number;
|
|
page_size: number;
|
|
}
|
|
|
|
export interface ProblemSummary {
|
|
id: number;
|
|
host_id: number | null;
|
|
hostname: string | null;
|
|
title: string;
|
|
summary: string;
|
|
severity: string;
|
|
status: string;
|
|
rule_id: string | null;
|
|
fingerprint?: string;
|
|
event_count?: number;
|
|
last_seen_at?: string;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
export interface ProblemListResponse {
|
|
items: ProblemSummary[];
|
|
total: number;
|
|
page: number;
|
|
page_size: number;
|
|
}
|
|
|
|
export interface ProblemEventItem {
|
|
id: number;
|
|
event_id: string;
|
|
occurred_at: string;
|
|
type: string;
|
|
severity: string;
|
|
title: string;
|
|
summary: string;
|
|
}
|
|
|
|
export interface ProblemDetail extends ProblemSummary {
|
|
events: ProblemEventItem[];
|
|
}
|
|
|
|
export function fetchProblem(id: number): Promise<ProblemDetail> {
|
|
return apiFetch<ProblemDetail>(`/api/v1/problems/${id}`);
|
|
}
|
|
|
|
export async function ackProblem(problemId: number): Promise<{ id: number; status: string }> {
|
|
return apiFetch(`/api/v1/problems/${problemId}/ack`, { method: "POST" });
|
|
}
|
|
|
|
export async function resolveProblem(problemId: number): Promise<{ id: number; status: string }> {
|
|
return apiFetch(`/api/v1/problems/${problemId}/resolve`, { method: "POST" });
|
|
}
|
|
|
|
export interface DashboardSummary {
|
|
events_last_24h: number;
|
|
hosts_total: number;
|
|
hosts_stale: number;
|
|
heartbeats_24h: number;
|
|
daily_reports_24h: number;
|
|
problems_open: number;
|
|
severity_24h: Record<string, number>;
|
|
recent_events: EventSummary[];
|
|
}
|