Improve agent detail, issue creation, and approvals pages
Expand AgentDetail with heartbeat history and manual trigger controls. Enhance NewIssueDialog with richer field options. Add agent connection string retrieval API. Improve issue routes with parent chain resolution. Clean up Approvals page layout. Update query keys and validators. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -153,6 +153,26 @@ export function agentService(db: Db) {
|
||||
};
|
||||
},
|
||||
|
||||
listKeys: (id: string) =>
|
||||
db
|
||||
.select({
|
||||
id: agentApiKeys.id,
|
||||
name: agentApiKeys.name,
|
||||
createdAt: agentApiKeys.createdAt,
|
||||
revokedAt: agentApiKeys.revokedAt,
|
||||
})
|
||||
.from(agentApiKeys)
|
||||
.where(eq(agentApiKeys.agentId, id)),
|
||||
|
||||
revokeKey: async (keyId: string) => {
|
||||
const rows = await db
|
||||
.update(agentApiKeys)
|
||||
.set({ revokedAt: new Date() })
|
||||
.where(eq(agentApiKeys.id, keyId))
|
||||
.returning();
|
||||
return rows[0] ?? null;
|
||||
},
|
||||
|
||||
orgForCompany: async (companyId: string) => {
|
||||
const rows = await db.select().from(agents).where(eq(agents.companyId, companyId));
|
||||
const byManager = new Map<string | null, typeof rows>();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { and, desc, eq, inArray, isNull, or, sql } from "drizzle-orm";
|
||||
import { and, asc, desc, eq, inArray, isNull, or, sql } from "drizzle-orm";
|
||||
import type { Db } from "@paperclip/db";
|
||||
import { agents, issues, issueComments } from "@paperclip/db";
|
||||
import { conflict, notFound, unprocessable } from "../errors.js";
|
||||
@@ -55,7 +55,8 @@ export function issueService(db: Db) {
|
||||
}
|
||||
if (filters?.projectId) conditions.push(eq(issues.projectId, filters.projectId));
|
||||
|
||||
return db.select().from(issues).where(and(...conditions)).orderBy(desc(issues.updatedAt));
|
||||
const priorityOrder = sql`CASE ${issues.priority} WHEN 'critical' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 WHEN 'low' THEN 3 ELSE 4 END`;
|
||||
return db.select().from(issues).where(and(...conditions)).orderBy(asc(priorityOrder), desc(issues.updatedAt));
|
||||
},
|
||||
|
||||
getById: (id: string) =>
|
||||
@@ -156,6 +157,11 @@ export function issueService(db: Db) {
|
||||
|
||||
if (!current) throw notFound("Issue not found");
|
||||
|
||||
// If this agent already owns it and it's in_progress, return it (no self-409)
|
||||
if (current.assigneeAgentId === agentId && current.status === "in_progress") {
|
||||
return db.select().from(issues).where(eq(issues.id, id)).then((rows) => rows[0]!);
|
||||
}
|
||||
|
||||
throw conflict("Issue checkout conflict", {
|
||||
issueId: current.id,
|
||||
status: current.status,
|
||||
|
||||
Reference in New Issue
Block a user