store only status-change events; UI client-side polling refactor
This commit is contained in:
102
web/src/lib/loaders.ts
Normal file
102
web/src/lib/loaders.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import "server-only";
|
||||
|
||||
import { ApiError, api, type Agent, type CheckState, type StoredEvent } from "@/lib/api";
|
||||
import type { components } from "@/lib/api-types";
|
||||
import { LIVENESS_CHECK_ID, withLivenessChecks, withLivenessEvents } from "@/lib/check-groups";
|
||||
import type { InventoryData, OverviewData } from "@/lib/view-types";
|
||||
|
||||
type Incident = components["schemas"]["Incident"];
|
||||
|
||||
export async function loadAgents(): Promise<Agent[]> {
|
||||
const agents: Agent[] = [];
|
||||
let cursor: string | undefined;
|
||||
do {
|
||||
const page = await api.listAgents({ cursor, limit: 500 });
|
||||
agents.push(...page.items);
|
||||
cursor = page.next_cursor ?? undefined;
|
||||
} while (cursor);
|
||||
return agents;
|
||||
}
|
||||
|
||||
export async function loadChecks(agentId?: string): Promise<CheckState[]> {
|
||||
const checks: CheckState[] = [];
|
||||
let cursor: string | undefined;
|
||||
do {
|
||||
const page = await api.listChecks({ agent_id: agentId, cursor, limit: 500 });
|
||||
checks.push(...page.items);
|
||||
cursor = page.next_cursor ?? undefined;
|
||||
} while (cursor);
|
||||
return checks;
|
||||
}
|
||||
|
||||
export async function loadInventory(): Promise<InventoryData> {
|
||||
const [agents, checks] = await Promise.all([loadAgents(), loadChecks()]);
|
||||
return { agents, checks: withLivenessChecks(agents, checks) };
|
||||
}
|
||||
|
||||
export async function loadEventsWithLiveness({
|
||||
agentId,
|
||||
checkId,
|
||||
cursor,
|
||||
limit,
|
||||
}: {
|
||||
agentId?: string;
|
||||
checkId?: string;
|
||||
cursor?: string;
|
||||
limit?: number;
|
||||
} = {}): Promise<{ items: StoredEvent[]; next_cursor?: string | null }> {
|
||||
const data = await api.queryEvents({ agent_id: agentId, check_id: checkId, cursor, limit });
|
||||
if (cursor || (checkId && checkId !== LIVENESS_CHECK_ID)) return data;
|
||||
|
||||
const agents = agentId ? await loadOptionalAgent(agentId) : await loadAgents();
|
||||
return {
|
||||
...data,
|
||||
items: withLivenessEvents(agents, data.items, { agentId, checkId, cursor }),
|
||||
};
|
||||
}
|
||||
|
||||
async function loadOptionalAgent(agentId: string): Promise<Agent[]> {
|
||||
try {
|
||||
return [await api.getAgent(agentId)];
|
||||
} catch (e) {
|
||||
if (e instanceof ApiError && e.status === 404) return [];
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadIncidents(
|
||||
state?: "open" | "resolved",
|
||||
): Promise<{ items: Incident[] }> {
|
||||
const items: Incident[] = [];
|
||||
let cursor: string | undefined;
|
||||
do {
|
||||
const page = await api.listIncidents({ state, cursor, limit: 500 });
|
||||
items.push(...page.items);
|
||||
cursor = page.next_cursor ?? undefined;
|
||||
} while (cursor);
|
||||
return { items };
|
||||
}
|
||||
|
||||
export async function loadOverview(): Promise<OverviewData> {
|
||||
const [agents, checks, incidents] = await Promise.all([
|
||||
loadAgents(),
|
||||
loadChecks(),
|
||||
api.listIncidents({ state: "open", limit: 500 }),
|
||||
]);
|
||||
const checksWithLiveness = withLivenessChecks(agents, checks);
|
||||
return {
|
||||
agents: tally(agents),
|
||||
checks: tally(checksWithLiveness),
|
||||
openIncidents: incidents.items.length,
|
||||
totalAgents: agents.length,
|
||||
totalChecks: checksWithLiveness.length,
|
||||
};
|
||||
}
|
||||
|
||||
function tally(xs: { status?: string }[]): Record<string, number> {
|
||||
return xs.reduce<Record<string, number>>((acc, x) => {
|
||||
const k = x.status ?? "unknown";
|
||||
acc[k] = (acc[k] ?? 0) + 1;
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
Reference in New Issue
Block a user