ab388b4f8c
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
108 lines
4.0 KiB
TypeScript
108 lines
4.0 KiB
TypeScript
/**
|
|
* Trace page Session-list logic (pure): mapping both server response shapes to the
|
|
* page's Session groups, and partitioning rows by their server-classified category.
|
|
*/
|
|
import { describe, expect, it } from "vitest";
|
|
import type { AgentTracesResponse } from "@prismshadow/penguin-server/api";
|
|
import { SIDEBAR_GROUP_PAGE_SIZE, SIDEBAR_PAGE_SIZE } from "../src/lib/session-grouping";
|
|
import {
|
|
TRACES_GROUP_PAGE_SIZE,
|
|
TRACES_PAGE_SIZE,
|
|
partitionTraceRows,
|
|
toSessionGroups,
|
|
} from "../src/features/traces/trace-sessions";
|
|
import type { TraceSessionRow } from "../src/features/traces/trace-sessions";
|
|
|
|
describe("trace page thresholds", () => {
|
|
it("stay larger than the sidebar's (full-height page column vs narrow sidebar), and bounded", () => {
|
|
expect(TRACES_PAGE_SIZE).toBeGreaterThan(SIDEBAR_PAGE_SIZE);
|
|
expect(TRACES_GROUP_PAGE_SIZE).toBeGreaterThan(SIDEBAR_GROUP_PAGE_SIZE);
|
|
// The fetch limit is TRACES_PAGE_SIZE + 1; the server caps limit at 1000.
|
|
expect(TRACES_PAGE_SIZE + 1).toBeLessThanOrEqual(1000);
|
|
});
|
|
});
|
|
|
|
const S1 = "session-2026-07-05-10-00-00-aabbccdd";
|
|
const S2 = "session-2026-07-06-09-00-00-11112222";
|
|
|
|
describe("toSessionGroups", () => {
|
|
it("paged response: server order kept, titles/classification carried, files re-sorted newest first", () => {
|
|
const res: AgentTracesResponse = {
|
|
dates: [],
|
|
sessions: [
|
|
{
|
|
sessionId: S2,
|
|
title: "标题",
|
|
category: "subagent",
|
|
workspace: "/ws/one",
|
|
files: [
|
|
{ index: 1, date: "2026-07-06", sizeBytes: 10 },
|
|
{ index: 2, date: "2026-07-07", sizeBytes: 20 },
|
|
],
|
|
},
|
|
{
|
|
sessionId: S1,
|
|
category: "active",
|
|
workspace: "",
|
|
files: [{ index: 1, date: "2026-07-05", sizeBytes: 5 }],
|
|
},
|
|
],
|
|
totalSessions: 12,
|
|
};
|
|
const groups = toSessionGroups(res);
|
|
expect(groups.map((g) => g.sessionId)).toEqual([S2, S1]);
|
|
expect(groups[0]!.title).toBe("标题");
|
|
expect(groups[0]!.category).toBe("subagent");
|
|
expect(groups[0]!.workspace).toBe("/ws/one");
|
|
expect(groups[0]!.files.map((f) => f.index)).toEqual([2, 1]); // newest first for display
|
|
expect(groups[1]!.title).toBeUndefined();
|
|
});
|
|
|
|
it("legacy response: flattens date groups (merging a Session's files across dates), Sessions sorted by id descending, classification defaulted", () => {
|
|
const res: AgentTracesResponse = {
|
|
dates: [
|
|
{
|
|
date: "2026-07-06",
|
|
sessions: [
|
|
{ sessionId: S2, files: [{ index: 1, sizeBytes: 1 }] },
|
|
{ sessionId: S1, files: [{ index: 2, sizeBytes: 2 }] },
|
|
],
|
|
},
|
|
{ date: "2026-07-05", sessions: [{ sessionId: S1, files: [{ index: 1, sizeBytes: 3 }] }] },
|
|
],
|
|
};
|
|
const groups = toSessionGroups(res);
|
|
expect(groups.map((g) => g.sessionId)).toEqual([S2, S1]);
|
|
// S1's files merged across both dates, each carrying its own date, newest first.
|
|
expect(groups[1]!.files).toEqual([
|
|
{ index: 2, date: "2026-07-06", sizeBytes: 2 },
|
|
{ index: 1, date: "2026-07-05", sizeBytes: 3 },
|
|
]);
|
|
// No classification in the legacy shape: rows default to the active bucket / unknown workspace.
|
|
expect(groups[0]!.category).toBe("active");
|
|
expect(groups[0]!.workspace).toBe("");
|
|
});
|
|
});
|
|
|
|
describe("partitionTraceRows", () => {
|
|
it("splits rows by their server-classified category, preserving input order", () => {
|
|
const row = (sessionId: string, category: TraceSessionRow["category"]): TraceSessionRow => ({
|
|
sessionId,
|
|
category,
|
|
workspace: "",
|
|
files: [],
|
|
agentId: "a1",
|
|
});
|
|
const parts = partitionTraceRows([
|
|
row("s-4", "archived"),
|
|
row("s-3", "active"),
|
|
row("s-2", "subagent"),
|
|
row("s-1", "active"),
|
|
]);
|
|
expect(parts.active.map((r) => r.sessionId)).toEqual(["s-3", "s-1"]);
|
|
expect(parts.subagent.map((r) => r.sessionId)).toEqual(["s-2"]);
|
|
expect(parts.schedule).toEqual([]);
|
|
expect(parts.archived.map((r) => r.sessionId)).toEqual(["s-4"]);
|
|
});
|
|
});
|