148 lines
4.4 KiB
TypeScript
148 lines
4.4 KiB
TypeScript
import { type PrismaClientOrTransaction, prisma } from "~/db.server";
|
|
|
|
type ErrorGroupIdentifier = {
|
|
organizationId: string;
|
|
projectId: string;
|
|
environmentId: string;
|
|
taskIdentifier: string;
|
|
errorFingerprint: string;
|
|
};
|
|
|
|
export class ErrorGroupActions {
|
|
constructor(private readonly _prisma: PrismaClientOrTransaction = prisma) {}
|
|
|
|
async resolveError(
|
|
identifier: ErrorGroupIdentifier,
|
|
params: {
|
|
// Nullable: a resolve via an env API key has no acting user, so
|
|
// `resolvedBy` stays null. The dashboard always passes a userId; the
|
|
// API passes the `act.sub` user from a PAT/UAT-exchanged JWT, else null.
|
|
userId?: string | null;
|
|
resolvedInVersion?: string;
|
|
}
|
|
) {
|
|
const where = {
|
|
environmentId_taskIdentifier_errorFingerprint: {
|
|
environmentId: identifier.environmentId,
|
|
taskIdentifier: identifier.taskIdentifier,
|
|
errorFingerprint: identifier.errorFingerprint,
|
|
},
|
|
};
|
|
|
|
const now = new Date();
|
|
|
|
return this._prisma.errorGroupState.upsert({
|
|
where,
|
|
update: {
|
|
status: "RESOLVED",
|
|
resolvedAt: now,
|
|
resolvedInVersion: params.resolvedInVersion ?? null,
|
|
resolvedBy: params.userId ?? null,
|
|
ignoredUntil: null,
|
|
ignoredUntilOccurrenceRate: null,
|
|
ignoredUntilTotalOccurrences: null,
|
|
ignoredAtOccurrenceCount: null,
|
|
ignoredAt: null,
|
|
ignoredReason: null,
|
|
ignoredByUserId: null,
|
|
},
|
|
create: {
|
|
organizationId: identifier.organizationId,
|
|
projectId: identifier.projectId,
|
|
environmentId: identifier.environmentId,
|
|
taskIdentifier: identifier.taskIdentifier,
|
|
errorFingerprint: identifier.errorFingerprint,
|
|
status: "RESOLVED",
|
|
resolvedAt: now,
|
|
resolvedInVersion: params.resolvedInVersion ?? null,
|
|
resolvedBy: params.userId ?? null,
|
|
},
|
|
});
|
|
}
|
|
|
|
async ignoreError(
|
|
identifier: ErrorGroupIdentifier,
|
|
params: {
|
|
userId?: string | null;
|
|
duration?: number;
|
|
occurrenceRateThreshold?: number;
|
|
totalOccurrencesThreshold?: number;
|
|
occurrenceCountAtIgnoreTime?: number;
|
|
reason?: string;
|
|
}
|
|
) {
|
|
const where = {
|
|
environmentId_taskIdentifier_errorFingerprint: {
|
|
environmentId: identifier.environmentId,
|
|
taskIdentifier: identifier.taskIdentifier,
|
|
errorFingerprint: identifier.errorFingerprint,
|
|
},
|
|
};
|
|
|
|
const now = new Date();
|
|
const ignoredUntil = params.duration ? new Date(now.getTime() + params.duration) : null;
|
|
|
|
const data = {
|
|
status: "IGNORED" as const,
|
|
ignoredAt: now,
|
|
ignoredUntil,
|
|
ignoredUntilOccurrenceRate: params.occurrenceRateThreshold ?? null,
|
|
ignoredUntilTotalOccurrences: params.totalOccurrencesThreshold ?? null,
|
|
ignoredAtOccurrenceCount: params.occurrenceCountAtIgnoreTime ?? null,
|
|
ignoredReason: params.reason ?? null,
|
|
ignoredByUserId: params.userId ?? null,
|
|
resolvedAt: null,
|
|
resolvedInVersion: null,
|
|
resolvedBy: null,
|
|
};
|
|
|
|
return this._prisma.errorGroupState.upsert({
|
|
where,
|
|
update: data,
|
|
create: {
|
|
organizationId: identifier.organizationId,
|
|
projectId: identifier.projectId,
|
|
environmentId: identifier.environmentId,
|
|
taskIdentifier: identifier.taskIdentifier,
|
|
errorFingerprint: identifier.errorFingerprint,
|
|
...data,
|
|
},
|
|
});
|
|
}
|
|
|
|
async unresolveError(identifier: ErrorGroupIdentifier) {
|
|
const where = {
|
|
environmentId_taskIdentifier_errorFingerprint: {
|
|
environmentId: identifier.environmentId,
|
|
taskIdentifier: identifier.taskIdentifier,
|
|
errorFingerprint: identifier.errorFingerprint,
|
|
},
|
|
};
|
|
|
|
return this._prisma.errorGroupState.upsert({
|
|
where,
|
|
update: {
|
|
status: "UNRESOLVED",
|
|
resolvedAt: null,
|
|
resolvedInVersion: null,
|
|
resolvedBy: null,
|
|
ignoredUntil: null,
|
|
ignoredUntilOccurrenceRate: null,
|
|
ignoredUntilTotalOccurrences: null,
|
|
ignoredAtOccurrenceCount: null,
|
|
ignoredAt: null,
|
|
ignoredReason: null,
|
|
ignoredByUserId: null,
|
|
},
|
|
create: {
|
|
organizationId: identifier.organizationId,
|
|
projectId: identifier.projectId,
|
|
environmentId: identifier.environmentId,
|
|
taskIdentifier: identifier.taskIdentifier,
|
|
errorFingerprint: identifier.errorFingerprint,
|
|
status: "UNRESOLVED",
|
|
},
|
|
});
|
|
}
|
|
}
|