ba7bbdbbdb
* Remove run count from JobPresenter * Remove job/integration counts from org/projects query * Removed v2 counts from ProjectPresenter query * JobRun index idx_jobrun_organizationId_createdAt * JobRun index idx_jobrun_versionId * BatchTaskRunItem index taskRunAttemptId * BatchTaskRunItem index taskRunId
211 lines
5.6 KiB
TypeScript
211 lines
5.6 KiB
TypeScript
import {
|
|
DisplayProperty,
|
|
DisplayPropertySchema,
|
|
EventSpecificationSchema,
|
|
TriggerHelpSchema,
|
|
} from "@trigger.dev/core";
|
|
import { PrismaClient, Prisma, prisma } from "~/db.server";
|
|
import { Organization } from "~/models/organization.server";
|
|
import { Project } from "~/models/project.server";
|
|
import { User } from "~/models/user.server";
|
|
import { z } from "zod";
|
|
import { projectPath } from "~/utils/pathBuilder";
|
|
import { Job } from "@trigger.dev/database";
|
|
import { BasePresenter } from "./v3/basePresenter.server";
|
|
|
|
export class JobPresenter extends BasePresenter {
|
|
public async call({
|
|
userId,
|
|
jobSlug,
|
|
projectSlug,
|
|
organizationSlug,
|
|
}: {
|
|
userId: User["id"];
|
|
jobSlug: Job["slug"];
|
|
projectSlug: Project["slug"];
|
|
organizationSlug: Organization["slug"];
|
|
}) {
|
|
const job = await this._replica.job.findFirst({
|
|
select: {
|
|
id: true,
|
|
slug: true,
|
|
title: true,
|
|
aliases: {
|
|
select: {
|
|
version: {
|
|
select: {
|
|
version: true,
|
|
eventSpecification: true,
|
|
properties: true,
|
|
status: true,
|
|
concurrencyLimit: true,
|
|
concurrencyLimitGroup: {
|
|
select: {
|
|
name: true,
|
|
concurrencyLimit: true,
|
|
},
|
|
},
|
|
runs: {
|
|
select: {
|
|
createdAt: true,
|
|
status: true,
|
|
},
|
|
take: 1,
|
|
orderBy: [{ createdAt: "desc" }],
|
|
},
|
|
integrations: {
|
|
select: {
|
|
key: true,
|
|
integration: {
|
|
select: {
|
|
slug: true,
|
|
definition: true,
|
|
setupStatus: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
triggerLink: true,
|
|
triggerHelp: true,
|
|
},
|
|
},
|
|
environment: {
|
|
select: {
|
|
type: true,
|
|
orgMember: {
|
|
select: {
|
|
userId: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
where: {
|
|
name: "latest",
|
|
},
|
|
},
|
|
dynamicTriggers: {
|
|
select: {
|
|
type: true,
|
|
},
|
|
},
|
|
project: {
|
|
select: {
|
|
slug: true,
|
|
},
|
|
},
|
|
},
|
|
where: {
|
|
slug: jobSlug,
|
|
deletedAt: null,
|
|
organization: {
|
|
members: {
|
|
some: {
|
|
userId,
|
|
},
|
|
},
|
|
},
|
|
project: {
|
|
slug: projectSlug,
|
|
},
|
|
},
|
|
});
|
|
|
|
if (!job) {
|
|
return undefined;
|
|
}
|
|
|
|
//the best alias to select:
|
|
// 1. Logged-in user dev
|
|
// 2. Prod
|
|
// 3. Any other user's dev
|
|
const sortedAliases = job.aliases.sort((a, b) => {
|
|
if (a.environment.type === "DEVELOPMENT" && a.environment.orgMember?.userId === userId) {
|
|
return -1;
|
|
}
|
|
|
|
if (b.environment.type === "DEVELOPMENT" && b.environment.orgMember?.userId === userId) {
|
|
return 1;
|
|
}
|
|
|
|
if (a.environment.type === "PRODUCTION") {
|
|
return -1;
|
|
}
|
|
|
|
if (b.environment.type === "PRODUCTION") {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
});
|
|
|
|
const alias = sortedAliases.at(0);
|
|
|
|
if (!alias) {
|
|
throw new Error(`No aliases found for job ${job.id}, this should never happen.`);
|
|
}
|
|
|
|
const eventSpecification = EventSpecificationSchema.parse(alias.version.eventSpecification);
|
|
|
|
const lastRuns = job.aliases
|
|
.map((alias) => alias.version.runs.at(0))
|
|
.filter(Boolean)
|
|
.sort((a, b) => {
|
|
return b.createdAt.getTime() - a.createdAt.getTime();
|
|
});
|
|
|
|
const lastRun = lastRuns.at(0);
|
|
|
|
const integrations = alias.version.integrations.map((integration) => ({
|
|
key: integration.key,
|
|
title: integration.integration.slug,
|
|
icon: integration.integration.definition.icon ?? integration.integration.definition.id,
|
|
setupStatus: integration.integration.setupStatus,
|
|
}));
|
|
|
|
let properties: DisplayProperty[] = [];
|
|
|
|
if (eventSpecification.properties) {
|
|
properties = [...properties, ...eventSpecification.properties];
|
|
}
|
|
|
|
if (alias.version.properties) {
|
|
const versionProperties = z.array(DisplayPropertySchema).parse(alias.version.properties);
|
|
properties = [...properties, ...versionProperties];
|
|
}
|
|
|
|
const environments = job.aliases.map((alias) => ({
|
|
type: alias.environment.type,
|
|
enabled: alias.version.status === "ACTIVE",
|
|
lastRun: alias.version.runs.at(0)?.createdAt,
|
|
version: alias.version.version,
|
|
concurrencyLimit: alias.version.concurrencyLimit,
|
|
concurrencyLimitGroup: alias.version.concurrencyLimitGroup,
|
|
}));
|
|
|
|
const projectRootPath = projectPath({ slug: organizationSlug }, { slug: projectSlug });
|
|
|
|
return {
|
|
id: job.id,
|
|
slug: job.slug,
|
|
title: job.title,
|
|
version: alias.version.version,
|
|
status: alias.version.status,
|
|
dynamic: job.dynamicTriggers.length > 0,
|
|
event: {
|
|
title: eventSpecification.title,
|
|
icon: eventSpecification.icon,
|
|
source: eventSpecification.source,
|
|
link: alias.version.triggerLink
|
|
? `${projectRootPath}/${alias.version.triggerLink}`
|
|
: undefined,
|
|
},
|
|
integrations,
|
|
hasIntegrationsRequiringAction: integrations.some((i) => i.setupStatus === "MISSING_FIELDS"),
|
|
lastRun,
|
|
properties,
|
|
environments,
|
|
};
|
|
}
|
|
}
|