frontend
This commit is contained in:
79
frontend/src/activeConfigSelection.test.ts
Normal file
79
frontend/src/activeConfigSelection.test.ts
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import { chooseActiveConfigItem, chooseDisplayItemsByPipeline } from "./activeConfigSelection";
|
||||||
|
import type { GraphConfigListItem } from "./types";
|
||||||
|
|
||||||
|
const mk = (patch: Partial<GraphConfigListItem>): GraphConfigListItem => ({
|
||||||
|
graph_id: "routing",
|
||||||
|
pipeline_id: "agent-a",
|
||||||
|
prompt_set_id: "set-1",
|
||||||
|
name: "default",
|
||||||
|
description: "",
|
||||||
|
is_active: false,
|
||||||
|
tool_keys: [],
|
||||||
|
api_key: "",
|
||||||
|
created_at: null,
|
||||||
|
updated_at: null,
|
||||||
|
...patch,
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("chooseActiveConfigItem", () => {
|
||||||
|
it("prefers active item over newer inactive items", () => {
|
||||||
|
const items = [
|
||||||
|
mk({
|
||||||
|
pipeline_id: "agent-a",
|
||||||
|
prompt_set_id: "old-active",
|
||||||
|
is_active: true,
|
||||||
|
updated_at: "2025-01-01T00:00:00Z",
|
||||||
|
}),
|
||||||
|
mk({
|
||||||
|
pipeline_id: "agent-a",
|
||||||
|
prompt_set_id: "new-inactive",
|
||||||
|
is_active: false,
|
||||||
|
updated_at: "2025-03-01T00:00:00Z",
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
const selected = chooseActiveConfigItem(items, "agent-a");
|
||||||
|
expect(selected?.prompt_set_id).toBe("old-active");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("falls back to latest updated_at when no active item exists", () => {
|
||||||
|
const items = [
|
||||||
|
mk({
|
||||||
|
pipeline_id: "agent-b",
|
||||||
|
prompt_set_id: "set-1",
|
||||||
|
updated_at: "2025-01-01T00:00:00Z",
|
||||||
|
}),
|
||||||
|
mk({
|
||||||
|
pipeline_id: "agent-b",
|
||||||
|
prompt_set_id: "set-2",
|
||||||
|
updated_at: "2025-02-01T00:00:00Z",
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
const selected = chooseActiveConfigItem(items, "agent-b");
|
||||||
|
expect(selected?.prompt_set_id).toBe("set-2");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("chooseDisplayItemsByPipeline", () => {
|
||||||
|
it("returns one selected item per pipeline_id", () => {
|
||||||
|
const items = [
|
||||||
|
mk({ pipeline_id: "agent-b", prompt_set_id: "set-1", updated_at: "2025-01-01T00:00:00Z" }),
|
||||||
|
mk({
|
||||||
|
pipeline_id: "agent-b",
|
||||||
|
prompt_set_id: "set-2",
|
||||||
|
is_active: true,
|
||||||
|
updated_at: "2025-02-01T00:00:00Z",
|
||||||
|
}),
|
||||||
|
mk({
|
||||||
|
pipeline_id: "agent-a",
|
||||||
|
prompt_set_id: "set-3",
|
||||||
|
updated_at: "2025-03-01T00:00:00Z",
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
const selected = chooseDisplayItemsByPipeline(items);
|
||||||
|
expect(selected.map((x) => x.pipeline_id)).toEqual(["agent-a", "agent-b"]);
|
||||||
|
expect(selected.find((x) => x.pipeline_id === "agent-b")?.prompt_set_id).toBe("set-2");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
45
frontend/src/activeConfigSelection.ts
Normal file
45
frontend/src/activeConfigSelection.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import type { GraphConfigListItem } from "./types";
|
||||||
|
|
||||||
|
function toTimestamp(value?: string | null): number {
|
||||||
|
if (!value) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const parsed = Date.parse(value);
|
||||||
|
return Number.isNaN(parsed) ? 0 : parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function chooseActiveConfigItem(
|
||||||
|
items: GraphConfigListItem[],
|
||||||
|
pipelineId: string
|
||||||
|
): GraphConfigListItem | null {
|
||||||
|
const candidates = items.filter((item) => item.pipeline_id === pipelineId);
|
||||||
|
if (candidates.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const active = candidates.find((item) => item.is_active);
|
||||||
|
if (active) {
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
return [...candidates].sort((a, b) => toTimestamp(b.updated_at) - toTimestamp(a.updated_at))[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function chooseDisplayItemsByPipeline(
|
||||||
|
items: GraphConfigListItem[]
|
||||||
|
): GraphConfigListItem[] {
|
||||||
|
const byPipeline = new Map<string, GraphConfigListItem[]>();
|
||||||
|
for (const item of items) {
|
||||||
|
const list = byPipeline.get(item.pipeline_id) || [];
|
||||||
|
list.push(item);
|
||||||
|
byPipeline.set(item.pipeline_id, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
const out: GraphConfigListItem[] = [];
|
||||||
|
for (const [pipelineId, list] of byPipeline.entries()) {
|
||||||
|
const selected = chooseActiveConfigItem(list, pipelineId);
|
||||||
|
if (selected) {
|
||||||
|
out.push(selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out.sort((a, b) => a.pipeline_id.localeCompare(b.pipeline_id));
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user