fix(issues): support hidden issue flows and filter hidden activity
This commit is contained in:
@@ -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" });
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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" });
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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()}`,
|
||||
),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user