import { type PrismaClientOrTransaction, type RuntimeEnvironmentType, type TaskTriggerSource, } from "@trigger.dev/database"; import { $replica } from "~/db.server"; import { clickhouseFactory } from "~/services/clickhouse/clickhouseFactoryInstance.server"; import { type AverageDurations, ClickHouseEnvironmentMetricsRepository, type CurrentRunningStats, type DailyTaskActivity, } from "~/services/environmentMetricsRepository.server"; import { singleton } from "~/utils/singleton"; import { findCurrentWorkerFromEnvironment } from "~/v3/models/workerDeployment.server"; export type TaskListItem = { slug: string; filePath: string; createdAt: Date; triggerSource: TaskTriggerSource; }; export type TaskActivity = DailyTaskActivity[string]; export class TaskListPresenter { constructor(private readonly _replica: PrismaClientOrTransaction) {} public async call({ organizationId, projectId, environmentId, environmentType, currentWorker: preloadedCurrentWorker, }: { organizationId: string; projectId: string; environmentId: string; environmentType: RuntimeEnvironmentType; /** Optional: pass the pre-resolved current worker to skip the lookup. Used * by `UnifiedTaskListPresenter` to share one lookup across both presenters. */ currentWorker?: Awaited>; }) { const currentWorker = preloadedCurrentWorker !== undefined ? preloadedCurrentWorker : await findCurrentWorkerFromEnvironment( { id: environmentId, type: environmentType, }, this._replica ); if (!currentWorker) { return { tasks: [], activity: Promise.resolve({} as DailyTaskActivity), runningStats: Promise.resolve({} as CurrentRunningStats), durations: Promise.resolve({} as AverageDurations), }; } const tasks = await this._replica.backgroundWorkerTask.findMany({ where: { workerId: currentWorker.id, triggerSource: { not: "AGENT" }, }, select: { id: true, slug: true, filePath: true, triggerSource: true, createdAt: true, }, orderBy: { slug: "asc", }, }); const slugs = tasks.map((t) => t.slug); // Create org-specific environment metrics repository const clickhouse = await clickhouseFactory.getClickhouseForOrganization( organizationId, "standard" ); const environmentMetricsRepository = new ClickHouseEnvironmentMetricsRepository({ clickhouse, }); // IMPORTANT: Don't await these, we want to return the promises // so we can defer the loading of the data const activity = environmentMetricsRepository.getDailyTaskActivity({ organizationId, projectId, environmentId, days: 6, // This actually means 7 days, because we want to show the current day too tasks: slugs, }); const runningStats = environmentMetricsRepository.getCurrentRunningStats({ organizationId, projectId, environmentId, days: 6, tasks: slugs, }); const durations = environmentMetricsRepository.getAverageDurations({ organizationId, projectId, environmentId, days: 6, tasks: slugs, }); return { tasks, activity, runningStats, durations }; } } export const taskListPresenter = singleton("taskListPresenter", setupTaskListPresenter); function setupTaskListPresenter() { return new TaskListPresenter($replica); }