feat: SSE real-time trace streaming + advanced search/filter with URL sync
This commit is contained in:
@@ -254,6 +254,10 @@ export async function GET(request: NextRequest) {
|
||||
const status = searchParams.get("status");
|
||||
const search = searchParams.get("search");
|
||||
const sessionId = searchParams.get("sessionId");
|
||||
const tags = searchParams.get("tags");
|
||||
const sort = searchParams.get("sort") ?? "newest";
|
||||
const dateFrom = searchParams.get("dateFrom");
|
||||
const dateTo = searchParams.get("dateTo");
|
||||
|
||||
// Validate pagination parameters
|
||||
if (isNaN(page) || page < 1) {
|
||||
@@ -269,6 +273,20 @@ export async function GET(request: NextRequest) {
|
||||
return NextResponse.json({ error: `Invalid status. Must be one of: ${validStatuses.join(", ")}` }, { status: 400 });
|
||||
}
|
||||
|
||||
// Validate sort parameter
|
||||
const validSorts = ["newest", "oldest", "longest", "shortest", "costliest"];
|
||||
if (sort && !validSorts.includes(sort)) {
|
||||
return NextResponse.json({ error: `Invalid sort. Must be one of: ${validSorts.join(", ")}` }, { status: 400 });
|
||||
}
|
||||
|
||||
// Validate date parameters
|
||||
if (dateFrom && isNaN(Date.parse(dateFrom))) {
|
||||
return NextResponse.json({ error: "Invalid dateFrom parameter. Must be a valid ISO date string." }, { status: 400 });
|
||||
}
|
||||
if (dateTo && isNaN(Date.parse(dateTo))) {
|
||||
return NextResponse.json({ error: "Invalid dateTo parameter. Must be a valid ISO date string." }, { status: 400 });
|
||||
}
|
||||
|
||||
// Build where clause
|
||||
const where: Record<string, unknown> = {};
|
||||
if (status) {
|
||||
@@ -283,6 +301,50 @@ export async function GET(request: NextRequest) {
|
||||
if (sessionId) {
|
||||
where.sessionId = sessionId;
|
||||
}
|
||||
if (tags) {
|
||||
const tagList = tags.split(",").map((t) => t.trim()).filter(Boolean);
|
||||
if (tagList.length > 0) {
|
||||
where.tags = {
|
||||
hasSome: tagList,
|
||||
};
|
||||
}
|
||||
}
|
||||
if (dateFrom) {
|
||||
where.createdAt = {
|
||||
...((where.createdAt as Prisma.TraceWhereInput) ?? {}),
|
||||
gte: new Date(dateFrom),
|
||||
};
|
||||
}
|
||||
if (dateTo) {
|
||||
where.createdAt = {
|
||||
...((where.createdAt as Prisma.TraceWhereInput) ?? {}),
|
||||
lte: new Date(dateTo),
|
||||
};
|
||||
}
|
||||
|
||||
// Build order by clause based on sort parameter
|
||||
let orderBy: Prisma.TraceOrderByWithRelationInput = {
|
||||
startedAt: "desc",
|
||||
};
|
||||
|
||||
switch (sort) {
|
||||
case "oldest":
|
||||
orderBy = { startedAt: "asc" };
|
||||
break;
|
||||
case "longest":
|
||||
orderBy = { totalDuration: "desc" };
|
||||
break;
|
||||
case "shortest":
|
||||
orderBy = { totalDuration: "asc" };
|
||||
break;
|
||||
case "costliest":
|
||||
orderBy = { totalCost: "desc" };
|
||||
break;
|
||||
case "newest":
|
||||
default:
|
||||
orderBy = { startedAt: "desc" };
|
||||
break;
|
||||
}
|
||||
|
||||
// Count total traces
|
||||
const total = await prisma.trace.count({ where });
|
||||
@@ -303,9 +365,7 @@ export async function GET(request: NextRequest) {
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: {
|
||||
startedAt: "desc",
|
||||
},
|
||||
orderBy,
|
||||
skip,
|
||||
take: limit,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user