From 1c98eb2b6196eb77c6c015af8fa54a5d6cf709e3 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Fri, 15 Mar 2024 10:32:07 +0000 Subject: [PATCH] Use TaskRunStatus (instead of TaskRunAttemptStatus) (#944) * Using the new run status instead of run attempt status * The test page now uses the TaskRunStatus as well * Organized imports * Use TaskRun icons instead of attempt ones * 10x zoom on the run timeline --- .../app/components/runs/v3/RunFilters.tsx | 22 +-- .../runs/v3/TaskRunAttemptStatus.tsx | 132 ++++++++++++++++++ .../app/components/runs/v3/TaskRunStatus.tsx | 81 ++++++----- .../app/components/runs/v3/TaskRunsTable.tsx | 4 +- .../presenters/v3/RunListPresenter.server.ts | 26 ++-- .../presenters/v3/TaskListPresenter.server.ts | 35 +++-- .../presenters/v3/TestTaskPresenter.server.ts | 18 +-- .../route.tsx | 36 +++-- .../route.tsx | 4 +- .../route.tsx | 13 +- .../route.tsx | 4 +- 11 files changed, 255 insertions(+), 120 deletions(-) create mode 100644 apps/webapp/app/components/runs/v3/TaskRunAttemptStatus.tsx diff --git a/apps/webapp/app/components/runs/v3/RunFilters.tsx b/apps/webapp/app/components/runs/v3/RunFilters.tsx index 345f0b5ee..f543e3d7d 100644 --- a/apps/webapp/app/components/runs/v3/RunFilters.tsx +++ b/apps/webapp/app/components/runs/v3/RunFilters.tsx @@ -1,6 +1,7 @@ import { TrashIcon } from "@heroicons/react/20/solid"; import { useNavigate } from "@remix-run/react"; -import { RuntimeEnvironment, TaskRunAttemptStatus } from "@trigger.dev/database"; +import { RuntimeEnvironment, TaskRunAttemptStatus, TaskRunStatus } from "@trigger.dev/database"; +import type { TaskRunStatus as TaskRunStatusType } from "@trigger.dev/database"; import { useCallback } from "react"; import { z } from "zod"; import { useOptimisticLocation } from "~/hooks/useOptimisticLocation"; @@ -16,21 +17,10 @@ import { SelectValue, } from "../../primitives/Select"; import { TimeFrameFilter } from "../TimeFrameFilter"; -import { TaskRunStatus } from "./TaskRunStatus"; +import { TaskRunStatusCombo } from "./TaskRunStatus"; -export const allTaskRunStatuses = [ - "ENQUEUED", - "PENDING", - "EXECUTING", - "PAUSED", - "FAILED", - "COMPLETED", - "CANCELED", -] as const; - -export type ExtendedTaskAttemptStatus = (typeof allTaskRunStatuses)[number]; - -export const TaskAttemptStatus = z.enum(allTaskRunStatuses); +export const allTaskRunStatuses = Object.values(TaskRunStatus) as TaskRunStatusType[]; +export const TaskAttemptStatus = z.nativeEnum(TaskRunStatus); export const TaskRunListSearchFilters = z.object({ cursor: z.string().optional(), @@ -174,7 +164,7 @@ export function RunsFilters({ possibleEnvironments, possibleTasks }: RunFiltersP {allTaskRunStatuses.map((status) => ( - + ))} diff --git a/apps/webapp/app/components/runs/v3/TaskRunAttemptStatus.tsx b/apps/webapp/app/components/runs/v3/TaskRunAttemptStatus.tsx new file mode 100644 index 000000000..5ca180655 --- /dev/null +++ b/apps/webapp/app/components/runs/v3/TaskRunAttemptStatus.tsx @@ -0,0 +1,132 @@ +import { + CheckCircleIcon, + ClockIcon, + NoSymbolIcon, + PauseCircleIcon, + RectangleStackIcon, + XCircleIcon, +} from "@heroicons/react/20/solid"; +import type { TaskRunAttemptStatus as TaskRunAttemptStatusType } from "@trigger.dev/database"; +import { TaskRunAttemptStatus } from "@trigger.dev/database"; +import { Spinner } from "~/components/primitives/Spinner"; +import { cn } from "~/utils/cn"; + +export const allTaskRunAttemptStatuses = Object.values( + TaskRunAttemptStatus +) as TaskRunAttemptStatusType[]; + +export type ExtendedTaskAttemptStatus = (typeof allTaskRunAttemptStatuses)[number] | "ENQUEUED"; + +export function TaskRunAttemptStatusCombo({ + status, + className, +}: { + status: ExtendedTaskAttemptStatus | null; + className?: string; +}) { + return ( + + + + + ); +} + +export function TaskRunAttemptStatusLabel({ + status, +}: { + status: ExtendedTaskAttemptStatus | null; +}) { + return ( + {runAttemptStatusTitle(status)} + ); +} + +export function TaskRunAttemptStatusIcon({ + status, + className, +}: { + status: ExtendedTaskAttemptStatus | null; + className: string; +}) { + if (status === null) { + return ; + } + + switch (status) { + case "ENQUEUED": + return ( + + ); + case "PENDING": + return ; + case "EXECUTING": + return ; + case "PAUSED": + return ; + case "FAILED": + return ; + case "CANCELED": + return ; + case "COMPLETED": + return ; + default: { + const _exhaustiveCheck: never = status; + throw new Error(`Non-exhaustive match for value: ${status}`); + } + } +} + +export function runAttemptStatusClassNameColor(status: ExtendedTaskAttemptStatus | null): string { + if (status === null) { + return "text-charcoal-500"; + } + + switch (status) { + case "ENQUEUED": + return "text-charcoal-500"; + case "PENDING": + return "text-charcoal-500"; + case "EXECUTING": + return "text-pending"; + case "PAUSED": + return "text-amber-300"; + case "FAILED": + return "text-error"; + case "CANCELED": + return "text-charcoal-500"; + case "COMPLETED": + return "text-success"; + default: { + const _exhaustiveCheck: never = status; + throw new Error(`Non-exhaustive match for value: ${status}`); + } + } +} + +export function runAttemptStatusTitle(status: ExtendedTaskAttemptStatus | null): string { + if (status === null) { + return "Enqueued"; + } + + switch (status) { + case "ENQUEUED": + return "Enqueued"; + case "PENDING": + return "Pending"; + case "EXECUTING": + return "Executing"; + case "PAUSED": + return "Paused"; + case "FAILED": + return "Failed"; + case "CANCELED": + return "Canceled"; + case "COMPLETED": + return "Completed"; + default: { + const _exhaustiveCheck: never = status; + throw new Error(`Non-exhaustive match for value: ${status}`); + } + } +} diff --git a/apps/webapp/app/components/runs/v3/TaskRunStatus.tsx b/apps/webapp/app/components/runs/v3/TaskRunStatus.tsx index 606b3677f..c4bc09988 100644 --- a/apps/webapp/app/components/runs/v3/TaskRunStatus.tsx +++ b/apps/webapp/app/components/runs/v3/TaskRunStatus.tsx @@ -1,4 +1,7 @@ import { + ArrowPathIcon, + BoltSlashIcon, + BugAntIcon, CheckCircleIcon, ClockIcon, NoSymbolIcon, @@ -6,15 +9,15 @@ import { RectangleStackIcon, XCircleIcon, } from "@heroicons/react/20/solid"; +import { TaskRunStatus } from "@trigger.dev/database"; import { Spinner } from "~/components/primitives/Spinner"; import { cn } from "~/utils/cn"; -import { ExtendedTaskAttemptStatus } from "./RunFilters"; -export function TaskRunStatus({ +export function TaskRunStatusCombo({ status, className, }: { - status: ExtendedTaskAttemptStatus | null; + status: TaskRunStatus; className?: string; }) { return ( @@ -25,7 +28,7 @@ export function TaskRunStatus({ ); } -export function TaskRunStatusLabel({ status }: { status: ExtendedTaskAttemptStatus | null }) { +export function TaskRunStatusLabel({ status }: { status: TaskRunStatus }) { return {runStatusTitle(status)}; } @@ -33,28 +36,30 @@ export function TaskRunStatusIcon({ status, className, }: { - status: ExtendedTaskAttemptStatus | null; + status: TaskRunStatus; className: string; }) { - if (status === null) { - return ; - } - switch (status) { - case "ENQUEUED": - return ; case "PENDING": - return ; + return ; case "EXECUTING": return ; + case "WAITING_TO_RESUME": + return ; + case "RETRYING_AFTER_FAILURE": + return ; case "PAUSED": return ; - case "FAILED": - return ; case "CANCELED": return ; - case "COMPLETED": + case "INTERRUPTED": + return ; + case "COMPLETED_SUCCESSFULLY": return ; + case "COMPLETED_WITH_ERRORS": + return ; + case "SYSTEM_FAILURE": + return ; default: { const _exhaustiveCheck: never = status; @@ -63,26 +68,28 @@ export function TaskRunStatusIcon({ } } -export function runStatusClassNameColor(status: ExtendedTaskAttemptStatus | null): string { - if (status === null) { - return "text-charcoal-500"; - } - +export function runStatusClassNameColor(status: TaskRunStatus): string { switch (status) { - case "ENQUEUED": - return "text-charcoal-500"; case "PENDING": return "text-charcoal-500"; case "EXECUTING": return "text-pending"; + case "WAITING_TO_RESUME": + return "text-charcoal-500"; + case "RETRYING_AFTER_FAILURE": + return "text-charcoal-500"; case "PAUSED": return "text-amber-300"; - case "FAILED": - return "text-error"; case "CANCELED": return "text-charcoal-500"; - case "COMPLETED": + case "INTERRUPTED": + return "text-error"; + case "COMPLETED_SUCCESSFULLY": return "text-success"; + case "COMPLETED_WITH_ERRORS": + return "text-error"; + case "SYSTEM_FAILURE": + return "text-error"; default: { const _exhaustiveCheck: never = status; throw new Error(`Non-exhaustive match for value: ${status}`); @@ -90,26 +97,28 @@ export function runStatusClassNameColor(status: ExtendedTaskAttemptStatus | null } } -export function runStatusTitle(status: ExtendedTaskAttemptStatus | null): string { - if (status === null) { - return "Enqueued"; - } - +export function runStatusTitle(status: TaskRunStatus): string { switch (status) { - case "ENQUEUED": - return "Enqueued"; case "PENDING": - return "Pending"; + return "Enqueued"; case "EXECUTING": return "Executing"; + case "WAITING_TO_RESUME": + return "Waiting"; + case "RETRYING_AFTER_FAILURE": + return "Retrying"; case "PAUSED": return "Paused"; - case "FAILED": - return "Failed"; case "CANCELED": return "Canceled"; - case "COMPLETED": + case "INTERRUPTED": + return "Interrupted"; + case "COMPLETED_SUCCESSFULLY": return "Completed"; + case "COMPLETED_WITH_ERRORS": + return "Failed"; + case "SYSTEM_FAILURE": + return "System failure"; default: { const _exhaustiveCheck: never = status; throw new Error(`Non-exhaustive match for value: ${status}`); diff --git a/apps/webapp/app/components/runs/v3/TaskRunsTable.tsx b/apps/webapp/app/components/runs/v3/TaskRunsTable.tsx index 654c84ea3..684bc8b73 100644 --- a/apps/webapp/app/components/runs/v3/TaskRunsTable.tsx +++ b/apps/webapp/app/components/runs/v3/TaskRunsTable.tsx @@ -19,8 +19,8 @@ import { TableHeaderCell, TableRow, } from "../../primitives/Table"; -import { TaskRunStatus } from "./TaskRunStatus"; import { formatDuration } from "@trigger.dev/core/v3"; +import { TaskRunStatusCombo } from "./TaskRunStatus"; type RunsTableProps = { total: number; @@ -82,7 +82,7 @@ export function TaskRunsTable({ - + {run.startedAt ? : "–"} diff --git a/apps/webapp/app/presenters/v3/RunListPresenter.server.ts b/apps/webapp/app/presenters/v3/RunListPresenter.server.ts index 922a6430a..37da01f31 100644 --- a/apps/webapp/app/presenters/v3/RunListPresenter.server.ts +++ b/apps/webapp/app/presenters/v3/RunListPresenter.server.ts @@ -1,6 +1,5 @@ -import { Prisma, TaskRunAttemptStatus } from "@trigger.dev/database"; +import { Prisma, TaskRunAttemptStatus, TaskRunStatus } from "@trigger.dev/database"; import { Direction } from "~/components/runs/RunStatuses"; -import { ExtendedTaskAttemptStatus } from "~/components/runs/v3/RunFilters"; import { PrismaClient, prisma } from "~/db.server"; import { getUsername } from "~/utils/username"; @@ -10,7 +9,7 @@ type RunListOptions = { //filters tasks: string[] | undefined; versions: string[] | undefined; - statuses: ExtendedTaskAttemptStatus[] | undefined; + statuses: TaskRunStatus[] | undefined; environments: string[] | undefined; from: number | undefined; to: number | undefined; @@ -45,10 +44,7 @@ export class RunListPresenter { cursor, pageSize = DEFAULT_PAGE_SIZE, }: RunListOptions) { - const filterByEnqueuedStatus = statuses ? statuses.includes("ENQUEUED") : false; - statuses = statuses ? statuses.filter((s) => s !== "ENQUEUED") : undefined; - const hasStatusFilters = - filterByEnqueuedStatus || (statuses !== undefined && statuses.length > 0); + const hasStatusFilters = statuses && statuses.length > 0; const hasFilters = tasks !== undefined || @@ -100,9 +96,9 @@ export class RunListPresenter { taskIdentifier: string; version: string | null; runtimeEnvironmentId: string; - status: TaskRunAttemptStatus | null; + status: TaskRunStatus; createdAt: Date; - startedAt: Date | null; + lockedAt: Date | null; completedAt: Date | null; isTest: boolean; attempts: BigInt; @@ -115,9 +111,9 @@ export class RunListPresenter { tr."taskIdentifier" AS "taskIdentifier", bw.version AS version, tr."runtimeEnvironmentId" AS "runtimeEnvironmentId", - tra.status AS status, + tr.status AS status, tr."createdAt" AS "createdAt", - tra."startedAt" AS "startedAt", + tr."lockedAt" AS "lockedAt", tra."completedAt" AS "completedAt", tr."isTest" AS "isTest", COUNT(tra.id) AS attempts @@ -151,11 +147,11 @@ export class RunListPresenter { ${hasStatusFilters ? Prisma.sql`AND (` : Prisma.empty} ${ statuses && statuses.length > 0 - ? Prisma.sql`tra.status = ANY(ARRAY[${Prisma.join(statuses)}]::"TaskRunAttemptStatus"[])` + ? Prisma.sql`tr.status = ANY(ARRAY[${Prisma.join(statuses)}]::"TaskRunStatus"[])` : Prisma.empty } - ${statuses && statuses.length > 0 && filterByEnqueuedStatus ? Prisma.sql` OR ` : Prisma.empty} - ${filterByEnqueuedStatus ? Prisma.sql`tra.status IS NULL` : Prisma.empty} + ${statuses && statuses.length > 0 && hasStatusFilters ? Prisma.sql` OR ` : Prisma.empty} + ${hasStatusFilters ? Prisma.sql`tr.status IS NULL` : Prisma.empty} ${hasStatusFilters ? Prisma.sql`) ` : Prisma.empty} ${ environments && environments.length > 0 @@ -217,7 +213,7 @@ export class RunListPresenter { friendlyId: run.runFriendlyId, number: Number(run.number), createdAt: run.createdAt, - startedAt: run.startedAt, + startedAt: run.lockedAt, completedAt: run.completedAt, isTest: run.isTest, status: run.status, diff --git a/apps/webapp/app/presenters/v3/TaskListPresenter.server.ts b/apps/webapp/app/presenters/v3/TaskListPresenter.server.ts index 93ae95302..98df20e8f 100644 --- a/apps/webapp/app/presenters/v3/TaskListPresenter.server.ts +++ b/apps/webapp/app/presenters/v3/TaskListPresenter.server.ts @@ -1,4 +1,4 @@ -import { Prisma, TaskRunAttemptStatus } from "@trigger.dev/database"; +import { Prisma, TaskRunAttemptStatus, TaskRunStatus } from "@trigger.dev/database"; import { PrismaClient, prisma } from "~/db.server"; import { Organization } from "~/models/organization.server"; import { Project } from "~/models/project.server"; @@ -79,35 +79,37 @@ export class TaskListPresenter { bwt."createdAt" DESC;`; let latestRuns = [] as { - updatedAt: Date; - status: TaskRunAttemptStatus; - backgroundWorkerTaskId: string; + createdAt: Date; + status: TaskRunStatus; + lockedById: string; }[]; if (tasks.length > 0) { latestRuns = await this.#prismaClient.$queryRaw< { - updatedAt: Date; - status: TaskRunAttemptStatus; - backgroundWorkerTaskId: string; + createdAt: Date; + status: TaskRunStatus; + lockedById: string; }[] >` SELECT * FROM ( SELECT - "updatedAt", + "createdAt", "status", - "backgroundWorkerTaskId", - ROW_NUMBER() OVER (PARTITION BY "backgroundWorkerTaskId" ORDER BY "updatedAt" DESC) AS rn + "lockedById", + ROW_NUMBER() OVER (PARTITION BY "lockedById" ORDER BY "updatedAt" DESC) AS rn FROM - "TaskRunAttempt" + "TaskRun" WHERE - "backgroundWorkerTaskId" IN(${Prisma.join(tasks.map((t) => t.id))}) + "lockedById" IN(${Prisma.join(tasks.map((t) => t.id))}) ) t WHERE rn = 1;`; + console.log(tasks.map((t) => t.id)); + console.log(latestRuns); } return tasks.map((task) => { - const latestRun = latestRuns.find((r) => r.backgroundWorkerTaskId === task.id); + const latestRun = latestRuns.find((r) => r.lockedById === task.id); const environment = project.environments.find((env) => env.id === task.runtimeEnvironmentId); if (!environment) { throw new Error(`Environment not found for TaskRun ${task.id}`); @@ -122,7 +124,12 @@ export class TaskListPresenter { userId: environment.orgMember?.user.id, userName: getUsername(environment.orgMember?.user), }, - latestRun, + latestRun: latestRun + ? { + createdAt: latestRun.createdAt, + status: latestRun.status, + } + : undefined, }; }); } diff --git a/apps/webapp/app/presenters/v3/TestTaskPresenter.server.ts b/apps/webapp/app/presenters/v3/TestTaskPresenter.server.ts index 536922315..46affe010 100644 --- a/apps/webapp/app/presenters/v3/TestTaskPresenter.server.ts +++ b/apps/webapp/app/presenters/v3/TestTaskPresenter.server.ts @@ -1,4 +1,4 @@ -import { TaskRunAttemptStatus } from "@trigger.dev/database"; +import { TaskRunAttemptStatus, TaskRunStatus } from "@trigger.dev/database"; import { PrismaClient, prisma } from "~/db.server"; import { getUsername } from "~/utils/username"; @@ -53,7 +53,7 @@ export class TestTaskPresenter { number: BigInt; friendlyId: string; createdAt: Date; - status: TaskRunAttemptStatus; + status: TaskRunStatus; payload: string; payloadType: string; runtimeEnvironmentId: string; @@ -73,13 +73,6 @@ export class TestTaskPresenter { ORDER BY tr."createdAt" DESC LIMIT 5 - ), latestattempts AS ( - SELECT - "taskRunId", - status, - ROW_NUMBER() OVER(PARTITION BY "taskRunId" ORDER BY "createdAt" DESC) AS rank - FROM - "TaskRunAttempt" ) SELECT taskr.id, @@ -87,17 +80,12 @@ export class TestTaskPresenter { taskr."friendlyId", taskr."taskIdentifier", taskr."createdAt", - tra.status, + taskr.status, taskr.payload, taskr."payloadType", taskr."runtimeEnvironmentId" FROM taskruns AS taskr - LEFT JOIN - latestattempts AS tra - ON taskr.id = tra."taskRunId" - WHERE - tra.rank = 1 ORDER BY taskr."createdAt" DESC;`; diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam._index/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam._index/route.tsx index fe7564fd1..14100b24e 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam._index/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam._index/route.tsx @@ -1,6 +1,6 @@ import { ChatBubbleLeftRightIcon } from "@heroicons/react/20/solid"; import { LoaderFunctionArgs } from "@remix-run/server-runtime"; -import { TaskRunAttemptStatus } from "@trigger.dev/database"; +import { TaskRunAttemptStatus, TaskRunStatus } from "@trigger.dev/database"; import { typedjson, useTypedLoaderData } from "remix-typedjson"; import invariant from "tiny-invariant"; import { Feedback } from "~/components/Feedback"; @@ -25,9 +25,8 @@ import { TableHeaderCell, TableRow, } from "~/components/primitives/Table"; -import { TaskPath } from "~/components/runs/v3/TaskPath"; -import { TaskRunStatus } from "~/components/runs/v3/TaskRunStatus"; -import { useAppOrigin } from "~/hooks/useAppOrigin"; +import { TaskFunctionName, TaskPath } from "~/components/runs/v3/TaskPath"; +import { TaskRunStatusCombo } from "~/components/runs/v3/TaskRunStatus"; import { useDevEnvironment } from "~/hooks/useEnvironments"; import { useOrganization } from "~/hooks/useOrganizations"; import { useProject } from "~/hooks/useProject"; @@ -83,8 +82,12 @@ export default function Page() { Task ID Task + Path Environment Last run + +
Last run status
+
Created at Go to page
@@ -104,32 +107,40 @@ export default function Page() { {task.slug} - + {task.filePath} + {task.latestRun ? (
- - +
) : ( "Never run" )}
+ + {task.latestRun ? ( + + ) : ( + "–" + )} + @@ -157,9 +168,10 @@ export default function Page() { ); } -function classForTaskAttemptStatus(status: TaskRunAttemptStatus) { +function classForTaskRunStatus(status: TaskRunStatus) { switch (status) { - case "FAILED": + case "SYSTEM_FAILURE": + case "COMPLETED_WITH_ERRORS": return "text-error"; default: return ""; diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.runs.$runParam.spans.$spanParam/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.runs.$runParam.spans.$spanParam/route.tsx index c3602f910..bfd6f091d 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.runs.$runParam.spans.$spanParam/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.runs.$runParam.spans.$spanParam/route.tsx @@ -15,7 +15,7 @@ import { RunIcon } from "~/components/runs/v3/RunIcon"; import { SpanEvents } from "~/components/runs/v3/SpanEvents"; import { SpanTitle } from "~/components/runs/v3/SpanTitle"; import { TaskPath } from "~/components/runs/v3/TaskPath"; -import { TaskRunStatus } from "~/components/runs/v3/TaskRunStatus"; +import { TaskRunAttemptStatusCombo } from "~/components/runs/v3/TaskRunAttemptStatus"; import { useOrganization } from "~/hooks/useOrganizations"; import { useProject } from "~/hooks/useProject"; import { SpanPresenter } from "~/presenters/v3/SpanPresenter.server"; @@ -85,7 +85,7 @@ export default function Page() { )} {event.style.variant === "primary" && ( -
@@ -384,8 +385,8 @@ function TasksTreeView({ durationMs={nanosecondsToMilliseconds(totalDuration * 1.05)} scale={scale} className="h-full overflow-hidden" - minWidth={initialTimelineDimensions?.width ?? 300} - maxWidth={2000} + minWidth={minTimelineWidth} + maxWidth={maxTimelineWidth} > {/* Follows the cursor */} @@ -568,14 +569,14 @@ function NodeStatusIcon({ node }: { node: RunEvent }) { } if (node.data.isError) { - return ; + return ; } if (node.data.isPartial) { return ; } - return ; + return ; } function TaskLine({ isError, isSelected }: { isError: boolean; isSelected: boolean }) { diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.test.tasks.$taskParam/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.test.tasks.$taskParam/route.tsx index a47f639b5..daab99267 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.test.tasks.$taskParam/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.test.tasks.$taskParam/route.tsx @@ -20,7 +20,7 @@ import { ResizablePanelGroup, } from "~/components/primitives/Resizable"; import { TaskPath } from "~/components/runs/v3/TaskPath"; -import { TaskRunStatus } from "~/components/runs/v3/TaskRunStatus"; +import { TaskRunStatusCombo } from "~/components/runs/v3/TaskRunStatus"; import { redirectBackWithErrorMessage, redirectWithSuccessMessage } from "~/models/message.server"; import { TestTaskPresenter } from "~/presenters/v3/TestTaskPresenter.server"; import { requireUserId } from "~/services/session.server"; @@ -209,7 +209,7 @@ export default function Page() {
Run #{run.number}
- +