Files
security-alert-center/frontend/src/api.ts
T
PapaTramp 249894d8e1 feat: UI Problems list filters, detail card and event timeline (d2-1)
- Filters status/severity/hostname; /problems/:id with Ack/Resolve and timeline

- Dashboard drill-down to open problems

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 09:55:28 +10:00

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[];
}