Skip to content

Commit 30df947

Browse files
committed
Fix for run page on wrong env. Added schedule last triggered column
1 parent 28cc9a5 commit 30df947

9 files changed

Lines changed: 73 additions & 27 deletions

File tree

apps/webapp/app/components/runs/v3/TaskRunsTable.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ export function TaskRunsTable({
288288
<BlankState isLoading={isLoading} filters={filters} />
289289
) : (
290290
runs.map((run, index) => {
291-
const path = v3RunSpanPath(organization, project, environment, run, {
291+
const path = v3RunSpanPath(organization, project, run.environment, run, {
292292
spanId: run.spanId,
293293
});
294294
return (

apps/webapp/app/presenters/v3/RunListPresenter.server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,8 @@ WHERE
425425
versions: versions || [],
426426
statuses: statuses || [],
427427
environments: environments || [],
428+
from: time.from,
429+
to: time.to,
428430
},
429431
hasFilters,
430432
hasAnyRuns,

apps/webapp/app/presenters/v3/RunPresenter.server.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { millisecondsToNanoseconds } from "@trigger.dev/core/v3";
22
import { createTreeFromFlatItems, flattenTree } from "~/components/primitives/TreeView/TreeView";
33
import { createTimelineSpanEventsFromSpanEvents } from "~/components/run/RunTimeline";
44
import { prisma, PrismaClient } from "~/db.server";
5+
import { redirectWithErrorMessage } from "~/models/message.server";
56
import { getUsername } from "~/utils/username";
67
import { eventRepository } from "~/v3/eventRepository.server";
78
import { getTaskEventStoreTableForRun } from "~/v3/taskEventStore.server";
@@ -11,6 +12,13 @@ type Result = Awaited<ReturnType<RunPresenter["call"]>>;
1112
export type Run = Result["run"];
1213
export type RunEvent = NonNullable<Result["trace"]>["events"][0];
1314

15+
export class RunEnvironmentMismatchError extends Error {
16+
constructor(message: string) {
17+
super(message);
18+
this.name = "RunEnvironmentMismatchError";
19+
}
20+
}
21+
1422
export class RunPresenter {
1523
#prismaClient: PrismaClient;
1624

@@ -22,12 +30,14 @@ export class RunPresenter {
2230
userId,
2331
projectSlug,
2432
organizationSlug,
33+
environmentSlug,
2534
runFriendlyId,
2635
showDeletedLogs,
2736
}: {
2837
userId: string;
2938
projectSlug: string;
3039
organizationSlug: string;
40+
environmentSlug: string;
3141
runFriendlyId: string;
3242
showDeletedLogs: boolean;
3343
}) {
@@ -79,6 +89,12 @@ export class RunPresenter {
7989
},
8090
});
8191

92+
if (environmentSlug !== run.runtimeEnvironment.slug) {
93+
throw new RunEnvironmentMismatchError(
94+
`Run ${runFriendlyId} is not in environment ${environmentSlug}`
95+
);
96+
}
97+
8298
const showLogs = showDeletedLogs || !run.logsDeletedAt;
8399

84100
const runData = {

apps/webapp/app/presenters/v3/ScheduleListPresenter.server.ts

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ export class ScheduleListPresenter extends BasePresenter {
162162
},
163163
},
164164
active: true,
165+
lastRunTriggeredAt: true,
165166
},
166167
where: {
167168
projectId: project.id,
@@ -209,23 +210,7 @@ export class ScheduleListPresenter extends BasePresenter {
209210
skip: (page - 1) * pageSize,
210211
});
211212

212-
const latestRuns =
213-
rawSchedules.length > 0
214-
? await this._replica.$queryRaw<{ scheduleId: string; createdAt: Date }[]>`
215-
SELECT t."scheduleId", t."createdAt"
216-
FROM (
217-
SELECT "scheduleId", MAX("createdAt") as "LatestRun"
218-
FROM ${sqlDatabaseSchema}."TaskRun"
219-
WHERE "scheduleId" IN (${Prisma.join(rawSchedules.map((s) => s.id))})
220-
GROUP BY "scheduleId"
221-
) r
222-
JOIN ${sqlDatabaseSchema}."TaskRun" t
223-
ON t."scheduleId" = r."scheduleId" AND t."createdAt" = r."LatestRun";`
224-
: [];
225-
226213
const schedules: ScheduleListItem[] = rawSchedules.map((schedule) => {
227-
const latestRun = latestRuns.find((r) => r.scheduleId === schedule.id);
228-
229214
return {
230215
id: schedule.id,
231216
type: schedule.type,
@@ -238,7 +223,7 @@ export class ScheduleListPresenter extends BasePresenter {
238223
timezone: schedule.timezone,
239224
active: schedule.active,
240225
externalId: schedule.externalId,
241-
lastRun: latestRun?.createdAt,
226+
lastRun: schedule.lastRunTriggeredAt ?? undefined,
242227
nextRun: calculateNextScheduledTimestamp(schedule.generatorExpression, schedule.timezone),
243228
environments: schedule.instances.map((instance) => {
244229
const environment = project.environments.find((env) => env.id === instance.environmentId);

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
formatDurationMilliseconds,
1919
millisecondsToNanoseconds,
2020
nanosecondsToMilliseconds,
21+
tryCatch,
2122
} from "@trigger.dev/core/v3";
2223
import { type RuntimeEnvironmentType } from "@trigger.dev/database";
2324
import { motion } from "framer-motion";
@@ -77,7 +78,7 @@ import { useProject } from "~/hooks/useProject";
7778
import { useReplaceSearchParams } from "~/hooks/useReplaceSearchParams";
7879
import { type Shortcut, useShortcutKeys } from "~/hooks/useShortcutKeys";
7980
import { useHasAdminAccess } from "~/hooks/useUser";
80-
import { RunPresenter } from "~/presenters/v3/RunPresenter.server";
81+
import { RunEnvironmentMismatchError, RunPresenter } from "~/presenters/v3/RunPresenter.server";
8182
import { getImpersonationId } from "~/services/impersonation.server";
8283
import { getResizableSnapshot } from "~/services/resizablePanel.server";
8384
import { requireUserId } from "~/services/session.server";
@@ -88,12 +89,15 @@ import {
8889
v3BillingPath,
8990
v3RunParamsSchema,
9091
v3RunPath,
92+
v3RunRedirectPath,
9193
v3RunSpanPath,
9294
v3RunStreamingPath,
9395
v3RunsPath,
9496
} from "~/utils/pathBuilder";
9597
import { useCurrentPlan } from "../_app.orgs.$organizationSlug/route";
9698
import { SpanView } from "../resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route";
99+
import { redirectWithErrorMessage } from "~/models/message.server";
100+
import { redirect } from "remix-typedjson";
97101

98102
const resizableSettings = {
99103
parent: {
@@ -133,13 +137,30 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
133137
const { projectParam, organizationSlug, envParam, runParam } = v3RunParamsSchema.parse(params);
134138

135139
const presenter = new RunPresenter();
136-
const result = await presenter.call({
137-
userId,
138-
organizationSlug,
139-
showDeletedLogs: !!impersonationId,
140-
projectSlug: projectParam,
141-
runFriendlyId: runParam,
142-
});
140+
const [error, result] = await tryCatch(
141+
presenter.call({
142+
userId,
143+
organizationSlug,
144+
showDeletedLogs: !!impersonationId,
145+
projectSlug: projectParam,
146+
runFriendlyId: runParam,
147+
environmentSlug: envParam,
148+
})
149+
);
150+
151+
if (error) {
152+
if (error instanceof RunEnvironmentMismatchError) {
153+
throw redirect(
154+
v3RunRedirectPath(
155+
{ slug: organizationSlug },
156+
{ slug: projectParam },
157+
{ friendlyId: runParam }
158+
)
159+
);
160+
}
161+
162+
throw error;
163+
}
143164

144165
//resizable settings
145166
const parent = await getResizableSnapshot(request, resizableSettings.parent.autosaveId);

apps/webapp/app/utils/pathBuilder.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,14 @@ export function v3RunPath(
242242
return `${v3RunsPath(organization, project, environment)}/${run.friendlyId}`;
243243
}
244244

245+
export function v3RunRedirectPath(
246+
organization: OrgForPath,
247+
project: ProjectForPath,
248+
run: v3RunForPath
249+
) {
250+
return `${v3ProjectPath(organization, project)}/runs/${run.friendlyId}`;
251+
}
252+
245253
export function v3RunDownloadLogsPath(run: v3RunForPath) {
246254
return `/resources/runs/${run.friendlyId}/logs/download`;
247255
}

apps/webapp/app/v3/services/triggerScheduledTask.server.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PrismaClientOrTransaction } from "~/db.server";
1+
import { type PrismaClientOrTransaction } from "~/db.server";
22
import { BaseService } from "./baseService.server";
33
import { workerQueue } from "~/services/worker.server";
44
import { RegisterNextTaskScheduleInstanceService } from "./registerNextTaskScheduleInstance.server";
@@ -147,6 +147,15 @@ export class TriggerScheduledTaskService extends BaseService {
147147
scheduleInstanceId: instance.id,
148148
},
149149
});
150+
151+
await this._prisma.taskSchedule.update({
152+
where: {
153+
id: instance.taskSchedule.id,
154+
},
155+
data: {
156+
lastRunTriggeredAt: new Date(),
157+
},
158+
});
150159
}
151160
}
152161

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
-- AlterTable
2+
ALTER TABLE "TaskSchedule"
3+
ADD COLUMN "lastRunTriggeredAt" TIMESTAMP(3);

internal-packages/database/prisma/schema.prisma

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2918,6 +2918,8 @@ model TaskSchedule {
29182918
///Instances of the schedule that are active
29192919
instances TaskScheduleInstance[]
29202920
2921+
lastRunTriggeredAt DateTime?
2922+
29212923
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
29222924
projectId String
29232925

0 commit comments

Comments
 (0)