mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-14 19:02:17 +03:00
feat(dashboard): overviewProjection — counters + kanban columns
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
/** OrchSnapshot → overview counters + kanban columns. Pure. */
|
||||
import {
|
||||
ORCH_STATES,
|
||||
type OrchNode,
|
||||
type OrchSnapshot,
|
||||
type OrchState,
|
||||
} from "./orchestrationTypes";
|
||||
|
||||
export interface OverviewData {
|
||||
counts: Record<OrchState, number>;
|
||||
columns: {
|
||||
queued: OrchNode[];
|
||||
running: OrchNode[];
|
||||
waiting_approval: OrchNode[];
|
||||
done: OrchNode[];
|
||||
};
|
||||
}
|
||||
|
||||
export function overviewProjection(snap: OrchSnapshot, comboActive: number): OverviewData {
|
||||
const counts = Object.fromEntries(ORCH_STATES.map((s) => [s, 0])) as Record<OrchState, number>;
|
||||
const columns: OverviewData["columns"] = {
|
||||
queued: [],
|
||||
running: [],
|
||||
waiting_approval: [],
|
||||
done: [],
|
||||
};
|
||||
|
||||
for (const n of snap.nodes) {
|
||||
if (n.kind !== "work" || !n.state) continue;
|
||||
counts[n.state] += 1;
|
||||
if (n.state === "queued" || n.state === "running" || n.state === "waiting_approval") {
|
||||
columns[n.state].push(n);
|
||||
} else {
|
||||
columns.done.push(n);
|
||||
}
|
||||
}
|
||||
columns.done.sort((a, b) => Date.parse(b.updatedAt ?? "0") - Date.parse(a.updatedAt ?? "0"));
|
||||
counts.running += comboActive;
|
||||
return { counts, columns };
|
||||
}
|
||||
47
tests/unit/ui/overviewProjection.test.ts
Normal file
47
tests/unit/ui/overviewProjection.test.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
/** Run: node --import tsx/esm --test tests/unit/ui/overviewProjection.test.ts */
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { overviewProjection } from "../../../src/app/(dashboard)/dashboard/orchestration/model/overviewProjection.ts";
|
||||
import type { OrchSnapshot } from "../../../src/app/(dashboard)/dashboard/orchestration/model/orchestrationTypes.ts";
|
||||
|
||||
const snap: OrchSnapshot = {
|
||||
nodes: [
|
||||
{ id: "orchestrator", kind: "orchestrator", label: "OmniRoute" },
|
||||
{ id: "cloud-agent:1", kind: "work", source: "cloud-agent", state: "running", label: "a" },
|
||||
{
|
||||
id: "cloud-agent:2",
|
||||
kind: "work",
|
||||
source: "cloud-agent",
|
||||
state: "waiting_approval",
|
||||
label: "b",
|
||||
},
|
||||
{
|
||||
id: "a2a:3",
|
||||
kind: "work",
|
||||
source: "a2a",
|
||||
state: "failed",
|
||||
label: "c",
|
||||
updatedAt: "2026-08-30T11:00:00Z",
|
||||
},
|
||||
{ id: "a2a:3:activity", kind: "activity", source: "a2a", state: "running", label: "noise" },
|
||||
],
|
||||
edges: [],
|
||||
sources: [],
|
||||
generatedAt: "2026-08-30T12:00:00Z",
|
||||
};
|
||||
|
||||
describe("overviewProjection", () => {
|
||||
it("counts only work nodes and adds comboActive to running", () => {
|
||||
const { counts } = overviewProjection(snap, 4);
|
||||
assert.equal(counts.running, 1 + 4);
|
||||
assert.equal(counts.waiting_approval, 1);
|
||||
assert.equal(counts.failed, 1);
|
||||
assert.equal(counts.queued, 0);
|
||||
});
|
||||
it("folds terminals into the done column", () => {
|
||||
const { columns } = overviewProjection(snap, 0);
|
||||
assert.equal(columns.done.length, 1);
|
||||
assert.equal(columns.done[0].id, "a2a:3");
|
||||
assert.equal(columns.running.length, 1);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user