feat(agent-api): GET /api/agent/projects/:projectId/cards
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
4fef9233c8
commit
9b6c031e60
1 changed files with 72 additions and 0 deletions
72
src/app/api/agent/projects/[projectId]/cards/route.ts
Normal file
72
src/app/api/agent/projects/[projectId]/cards/route.ts
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import { getAdminPb } from "@/lib/pb/admin";
|
||||
import { requireAgentToken } from "@/lib/agent/auth";
|
||||
import { jsonError, jsonOk } from "@/lib/http/json";
|
||||
import type { CardRecord, ColumnRecord } from "@/lib/pb/types";
|
||||
|
||||
/**
|
||||
* GET /api/agent/projects/:projectId/cards — every non-archived card in the
|
||||
* project, any column, in the same order the board itself renders in.
|
||||
*
|
||||
* `?column=inbox` filters to the Inbox column only, matching `is_inbox` —
|
||||
* never a literal column name, since column names are editable per project.
|
||||
*/
|
||||
export async function GET(
|
||||
request: Request,
|
||||
context: { params: Promise<{ projectId: string }> }
|
||||
): Promise<Response> {
|
||||
const denied = requireAgentToken(request);
|
||||
if (denied) return denied;
|
||||
|
||||
const { projectId } = await context.params;
|
||||
const pb = await getAdminPb();
|
||||
|
||||
const project = await pb.collection("projects").getOne(projectId).catch(() => null);
|
||||
if (!project) return jsonError("Project not found", 404);
|
||||
|
||||
const columns = await pb.collection("columns").getFullList<ColumnRecord>({
|
||||
filter: `project = "${projectId}"`,
|
||||
sort: "position",
|
||||
});
|
||||
const columnsById = new Map(columns.map((c) => [c.id, c]));
|
||||
|
||||
const url = new URL(request.url);
|
||||
const onlyInbox = url.searchParams.get("column") === "inbox";
|
||||
|
||||
let cards = await pb.collection("cards").getFullList<CardRecord>({
|
||||
filter: `project = "${projectId}" && archived = false`,
|
||||
});
|
||||
|
||||
if (onlyInbox) {
|
||||
cards = cards.filter((card) => columnsById.get(card.column)?.is_inbox === true);
|
||||
}
|
||||
|
||||
cards.sort((a, b) => {
|
||||
const colA = columnsById.get(a.column)?.position ?? 0;
|
||||
const colB = columnsById.get(b.column)?.position ?? 0;
|
||||
return colA - colB || a.position - b.position;
|
||||
});
|
||||
|
||||
const out = cards
|
||||
.map((card) => {
|
||||
const column = columnsById.get(card.column);
|
||||
if (!column) return null;
|
||||
return {
|
||||
id: card.id,
|
||||
number: card.number,
|
||||
title: card.title,
|
||||
description: card.description,
|
||||
priority: card.priority,
|
||||
target_date: card.target_date,
|
||||
size_band: card.size_band,
|
||||
column: {
|
||||
id: column.id,
|
||||
name: column.name,
|
||||
is_inbox: column.is_inbox,
|
||||
is_done: column.is_done,
|
||||
},
|
||||
};
|
||||
})
|
||||
.filter((c): c is NonNullable<typeof c> => c !== null);
|
||||
|
||||
return jsonOk(out);
|
||||
}
|
||||
Loading…
Reference in a new issue