store only status-change events; UI client-side polling refactor

This commit is contained in:
Stanislav Rossovskii
2026-05-27 14:58:46 +04:00
parent 71f0035b0b
commit d5f312f200
48 changed files with 2247 additions and 753 deletions

View File

@@ -19,7 +19,7 @@ const fixtures = {
{
agent_id: "agent-2",
hostname: "host-2",
status: "stale",
status: "dead",
last_seen_at: now,
features: { push: true, metrics: false },
labels: {},
@@ -44,6 +44,7 @@ const fixtures = {
exit_code: 0,
last_observed_at: now,
incident_key: "agent-1:disk",
summary: "disk ok",
},
{
agent_id: "agent-1",
@@ -52,6 +53,7 @@ const fixtures = {
exit_code: 1,
last_observed_at: now,
incident_key: "agent-1:load",
summary: "load high",
},
],
next_cursor: null,
@@ -68,6 +70,27 @@ const fixtures = {
opened_at: now,
summary: "load high",
},
{
id: "00000000-0000-0000-0000-000000000003",
incident_key: "agent:agent-2:liveness",
state: "open",
severity: "critical",
agent_id: "agent-2",
check_id: "agent_liveness",
opened_at: now,
summary: "agent is dead",
},
{
id: "00000000-0000-0000-0000-000000000004",
incident_key: "agent-2:disk",
state: "resolved",
severity: "critical",
agent_id: "agent-2",
check_id: "disk",
opened_at: now,
resolved_at: now,
summary: "disk recovered",
},
],
next_cursor: null,
},
@@ -82,6 +105,22 @@ const fixtures = {
status: "ok",
exit_code: 0,
duration_ms: 12,
output: "disk ok",
output_truncated: false,
notifications_enabled: true,
},
{
event_id: "00000000-0000-7000-8000-000000000002",
agent_id: "agent-1",
check_id: "load",
observed_at: now,
received_at: now,
status: "warning",
exit_code: 1,
duration_ms: 34,
output: "load high",
output_truncated: false,
notifications_enabled: true,
},
],
next_cursor: null,
@@ -117,6 +156,29 @@ const server = createServer((req, res) => {
};
}
}
if (url.pathname === "/api/v1/events/query" && body) {
const agentId = url.searchParams.get("agent_id");
const checkId = url.searchParams.get("check_id");
body = {
...body,
items: body.items.filter((item) => {
if (agentId && item.agent_id !== agentId) return false;
if (checkId && item.check_id !== checkId) return false;
return true;
}),
next_cursor: null,
};
}
if (url.pathname === "/api/v1/incidents" && body) {
const state = url.searchParams.get("state");
if (state) {
body = {
...body,
items: body.items.filter((item) => item.state === state),
next_cursor: null,
};
}
}
res.setHeader("Content-Type", "application/json");
if (!body) {
res.statusCode = 404;

View File

@@ -38,6 +38,8 @@ test("agents list links to detail", async ({ page }) => {
await expect(page.getByRole("link", { name: "Checks" }).last()).toBeVisible();
await expect(page.locator("tbody").first().locator("tr").first()).toContainText("warning");
await expect(page.locator("thead").first()).not.toContainText("incident_key");
await expect(page.locator("thead").first()).not.toContainText("exit");
await expect(page.locator("tbody").first()).toContainText("load high");
await page.getByRole("link", { name: "check_id" }).click();
await expect(page).toHaveURL(/sort=check_id/);
await page.getByRole("link", { name: "Events" }).last().click();
@@ -49,18 +51,57 @@ test("agents list links to detail", async ({ page }) => {
test("checks page lists rows", async ({ page }) => {
await page.goto("/checks");
await expect(page.getByRole("heading", { name: "Checks" })).toBeVisible();
await expect(page).toHaveURL(/\/checks$/);
await expect(page.locator("thead").first()).not.toContainText("agent_id");
await expect(page.locator("thead").first()).not.toContainText("incident_key");
await expect(page.locator("thead").first()).not.toContainText("exit");
await expect(page.locator("thead").first()).toContainText("↓");
await expect(page.locator("body")).toContainText("disk");
await expect(page.locator("body")).toContainText("load");
await expect(page.locator("body")).toContainText("agent_liveness");
await page.getByPlaceholder("search check").fill("lo");
await expect(page).toHaveURL(/\/checks$/);
await expect(page.locator("tbody")).toContainText("load");
await expect(page.locator("tbody")).not.toContainText("disk");
await page.getByRole("button", { name: "clear" }).click();
await page.getByRole("button", { name: /^CHECK/ }).click();
await expect(page).toHaveURL(/\/checks$/);
await page.getByRole("link", { name: "disk" }).click();
await expect(page).toHaveURL(/\/events\?agent_id=agent-1&check_id=disk$/);
await expect(page).toHaveURL(/\/checks\/disk$/);
await expect(page.getByRole("link", { name: "Agents" }).last()).toBeVisible();
await expect(page.locator("body")).toContainText("host-1");
await expect(page.locator("body")).toContainText("disk ok");
await page.getByRole("link", { name: "Events" }).last().click();
await expect(page).toHaveURL(/\/checks\/disk\?tab=events$/);
await expect(page.locator("body")).toContainText("12");
await expect(page.locator("thead").last()).not.toContainText("exit");
});
test("incidents filter renders", async ({ page }) => {
await page.goto("/incidents");
await expect(page.locator("body")).toContainText("load high");
await expect(page.locator("thead")).toContainText("HOST");
await expect(page.locator("thead")).not.toContainText("agent_id");
await expect(page.locator("thead")).toContainText("↓");
await expect(page.locator("tbody")).toContainText("host-1");
await expect(page.locator("tbody")).toContainText("agent_liveness");
await expect(page.locator("tbody")).toContainText("agent is dead");
await page.getByRole("link", { name: "agent_liveness" }).click();
await expect(page).toHaveURL(/\/checks\/agent_liveness$/);
await expect(page.locator("body")).toContainText("host-2");
await page.goto("/incidents");
await page.getByRole("button", { name: /^HOST/ }).click();
await expect(page).toHaveURL(/\/incidents$/);
await expect(page.locator("thead")).toContainText("↑");
await page.getByRole("link", { name: "host-1" }).click();
await expect(page).toHaveURL(/\/agents\/agent-1$/);
});
test("events page", async ({ page }) => {
await page.goto("/events");
await expect(page.locator("body")).toContainText("agent_liveness");
await expect(page.locator("body")).toContainText("agent is dead");
await page.goto("/events?agent_id=agent-1&check_id=disk");
await expect(page.getByRole("heading", { name: "Events" })).toBeVisible();
await expect(page.getByRole("button", { name: "query" })).toHaveCount(0);