fix(issues): support hidden issue flows and filter hidden activity

This commit is contained in:
Forgotten
2026-02-20 07:11:06 -06:00
parent 8f3fc077fa
commit f766478f5a
6 changed files with 50 additions and 8 deletions

View File

@@ -5,7 +5,7 @@ import { HttpError } from "../errors.js";
export function errorHandler(
err: unknown,
_req: Request,
req: Request,
res: Response,
_next: NextFunction,
) {
@@ -22,6 +22,16 @@ export function errorHandler(
return;
}
logger.error(err, "Unhandled error");
const errObj = err instanceof Error
? { message: err.message, stack: err.stack, name: err.name }
: { raw: err };
logger.error(
{ err: errObj, method: req.method, url: req.originalUrl },
"Unhandled error: %s %s — %s",
req.method,
req.originalUrl,
err instanceof Error ? err.message : String(err),
);
res.status(500).json({ error: "Internal server error" });
}

View File

@@ -19,7 +19,7 @@ export const logger = pino({
targets: [
{
target: "pino-pretty",
options: { ...sharedOpts, ignore: "pid,hostname,req,res", hideObject: true, colorize: true, destination: 1 },
options: { ...sharedOpts, ignore: "pid,hostname,req,res", colorize: true, destination: 1 },
level: "info",
},
{

View File

@@ -186,7 +186,10 @@ export function issueRoutes(db: Db) {
}
assertCompanyAccess(req, existing.companyId);
const { comment: commentBody, ...updateFields } = req.body;
const { comment: commentBody, hiddenAt: hiddenAtRaw, ...updateFields } = req.body;
if (hiddenAtRaw !== undefined) {
updateFields.hiddenAt = hiddenAtRaw ? new Date(hiddenAtRaw) : null;
}
const issue = await svc.update(id, updateFields);
if (!issue) {
res.status(404).json({ error: "Issue not found" });

View File

@@ -1,4 +1,4 @@
import { and, desc, eq, isNotNull, sql } from "drizzle-orm";
import { and, desc, eq, isNotNull, isNull, or, sql } from "drizzle-orm";
import type { Db } from "@paperclip/db";
import { activityLog, heartbeatRuns, issues } from "@paperclip/db";
@@ -25,7 +25,27 @@ export function activityService(db: Db) {
conditions.push(eq(activityLog.entityId, filters.entityId));
}
return db.select().from(activityLog).where(and(...conditions)).orderBy(desc(activityLog.createdAt));
return db
.select({ activityLog })
.from(activityLog)
.leftJoin(
issues,
and(
eq(activityLog.entityType, sql`'issue'`),
eq(activityLog.entityId, issueIdAsText),
),
)
.where(
and(
...conditions,
or(
sql`${activityLog.entityType} != 'issue'`,
isNull(issues.hiddenAt),
),
),
)
.orderBy(desc(activityLog.createdAt))
.then((rows) => rows.map((r) => r.activityLog));
},
forIssue: (issueId: string) =>
@@ -76,6 +96,7 @@ export function activityService(db: Db) {
and(
eq(activityLog.runId, runId),
eq(activityLog.entityType, "issue"),
isNull(issues.hiddenAt),
),
)
.orderBy(issueIdAsText),

View File

@@ -324,6 +324,7 @@ export function issueService(db: Db) {
and(
eq(issues.companyId, companyId),
eq(issues.status, "in_progress"),
isNull(issues.hiddenAt),
sql`${issues.startedAt} < ${cutoff.toISOString()}`,
),
)