forked from farhoodlabs/paperclip
c2709687b8
Add ILIKE-based issue search across title, identifier, description, and comments with relevance ranking. Add assigneeUserId filter and allow agents to return issues to creator. Show assigned issue count in sidebar badges. Add minCount param to live-runs endpoint. Add activity charts (run activity, priority, status, success rate) to dashboard. Improve active agents panel with recent run cards. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
56 lines
1.8 KiB
TypeScript
56 lines
1.8 KiB
TypeScript
import { and, desc, eq, inArray, not, sql } from "drizzle-orm";
|
|
import type { Db } from "@paperclip/db";
|
|
import { agents, approvals, heartbeatRuns } from "@paperclip/db";
|
|
import type { SidebarBadges } from "@paperclip/shared";
|
|
|
|
const ACTIONABLE_APPROVAL_STATUSES = ["pending", "revision_requested"];
|
|
const FAILED_HEARTBEAT_STATUSES = ["failed", "timed_out"];
|
|
|
|
export function sidebarBadgeService(db: Db) {
|
|
return {
|
|
get: async (
|
|
companyId: string,
|
|
extra?: { joinRequests?: number; assignedIssues?: number },
|
|
): Promise<SidebarBadges> => {
|
|
const actionableApprovals = await db
|
|
.select({ count: sql<number>`count(*)` })
|
|
.from(approvals)
|
|
.where(
|
|
and(
|
|
eq(approvals.companyId, companyId),
|
|
inArray(approvals.status, ACTIONABLE_APPROVAL_STATUSES),
|
|
),
|
|
)
|
|
.then((rows) => Number(rows[0]?.count ?? 0));
|
|
|
|
const latestRunByAgent = await db
|
|
.selectDistinctOn([heartbeatRuns.agentId], {
|
|
runStatus: heartbeatRuns.status,
|
|
})
|
|
.from(heartbeatRuns)
|
|
.innerJoin(agents, eq(heartbeatRuns.agentId, agents.id))
|
|
.where(
|
|
and(
|
|
eq(heartbeatRuns.companyId, companyId),
|
|
eq(agents.companyId, companyId),
|
|
not(eq(agents.status, "terminated")),
|
|
),
|
|
)
|
|
.orderBy(heartbeatRuns.agentId, desc(heartbeatRuns.createdAt));
|
|
|
|
const failedRuns = latestRunByAgent.filter((row) =>
|
|
FAILED_HEARTBEAT_STATUSES.includes(row.runStatus),
|
|
).length;
|
|
|
|
const joinRequests = extra?.joinRequests ?? 0;
|
|
const assignedIssues = extra?.assignedIssues ?? 0;
|
|
return {
|
|
inbox: actionableApprovals + failedRuns + joinRequests + assignedIssues,
|
|
approvals: actionableApprovals,
|
|
failedRuns,
|
|
joinRequests,
|
|
};
|
|
},
|
|
};
|
|
}
|