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
This commit is contained in:
Matt Aitken
2024-03-15 10:32:07 +00:00
committed by GitHub
parent f424c81086
commit 1c98eb2b61
11 changed files with 255 additions and 120 deletions
@@ -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
</SelectItem>
{allTaskRunStatuses.map((status) => (
<SelectItem key={status} value={status}>
<TaskRunStatus status={status} className="text-xs" />
<TaskRunStatusCombo status={status} className="text-xs" />
</SelectItem>
))}
</SelectContent>
@@ -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 (
<span className={cn("flex items-center gap-1", className)}>
<TaskRunAttemptStatusIcon status={status} className="h-4 w-4" />
<TaskRunAttemptStatusLabel status={status} />
</span>
);
}
export function TaskRunAttemptStatusLabel({
status,
}: {
status: ExtendedTaskAttemptStatus | null;
}) {
return (
<span className={runAttemptStatusClassNameColor(status)}>{runAttemptStatusTitle(status)}</span>
);
}
export function TaskRunAttemptStatusIcon({
status,
className,
}: {
status: ExtendedTaskAttemptStatus | null;
className: string;
}) {
if (status === null) {
return <RectangleStackIcon className={cn(runAttemptStatusClassNameColor(status), className)} />;
}
switch (status) {
case "ENQUEUED":
return (
<RectangleStackIcon className={cn(runAttemptStatusClassNameColor(status), className)} />
);
case "PENDING":
return <ClockIcon className={cn(runAttemptStatusClassNameColor(status), className)} />;
case "EXECUTING":
return <Spinner className={cn(runAttemptStatusClassNameColor(status), className)} />;
case "PAUSED":
return <PauseCircleIcon className={cn(runAttemptStatusClassNameColor(status), className)} />;
case "FAILED":
return <XCircleIcon className={cn(runAttemptStatusClassNameColor(status), className)} />;
case "CANCELED":
return <NoSymbolIcon className={cn(runAttemptStatusClassNameColor(status), className)} />;
case "COMPLETED":
return <CheckCircleIcon className={cn(runAttemptStatusClassNameColor(status), className)} />;
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}`);
}
}
}
@@ -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 <span className={runStatusClassNameColor(status)}>{runStatusTitle(status)}</span>;
}
@@ -33,28 +36,30 @@ export function TaskRunStatusIcon({
status,
className,
}: {
status: ExtendedTaskAttemptStatus | null;
status: TaskRunStatus;
className: string;
}) {
if (status === null) {
return <RectangleStackIcon className={cn(runStatusClassNameColor(status), className)} />;
}
switch (status) {
case "ENQUEUED":
return <RectangleStackIcon className={cn(runStatusClassNameColor(status), className)} />;
case "PENDING":
return <ClockIcon className={cn(runStatusClassNameColor(status), className)} />;
return <RectangleStackIcon className={cn(runStatusClassNameColor(status), className)} />;
case "EXECUTING":
return <Spinner className={cn(runStatusClassNameColor(status), className)} />;
case "WAITING_TO_RESUME":
return <ClockIcon className={cn(runStatusClassNameColor(status), className)} />;
case "RETRYING_AFTER_FAILURE":
return <ArrowPathIcon className={cn(runStatusClassNameColor(status), className)} />;
case "PAUSED":
return <PauseCircleIcon className={cn(runStatusClassNameColor(status), className)} />;
case "FAILED":
return <XCircleIcon className={cn(runStatusClassNameColor(status), className)} />;
case "CANCELED":
return <NoSymbolIcon className={cn(runStatusClassNameColor(status), className)} />;
case "COMPLETED":
case "INTERRUPTED":
return <BoltSlashIcon className={cn(runStatusClassNameColor(status), className)} />;
case "COMPLETED_SUCCESSFULLY":
return <CheckCircleIcon className={cn(runStatusClassNameColor(status), className)} />;
case "COMPLETED_WITH_ERRORS":
return <XCircleIcon className={cn(runStatusClassNameColor(status), className)} />;
case "SYSTEM_FAILURE":
return <BugAntIcon className={cn(runStatusClassNameColor(status), className)} />;
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}`);
@@ -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({
<EnvironmentLabel environment={run.environment} userName={usernameForEnv} />
</TableCell>
<TableCell to={path}>
<TaskRunStatus status={run.status} />
<TaskRunStatusCombo status={run.status} />
</TableCell>
<TableCell to={path}>
{run.startedAt ? <DateTime date={run.startedAt} /> : ""}
@@ -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,
@@ -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,
};
});
}
@@ -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;`;
@@ -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() {
<TableRow>
<TableHeaderCell>Task ID</TableHeaderCell>
<TableHeaderCell>Task</TableHeaderCell>
<TableHeaderCell>Path</TableHeaderCell>
<TableHeaderCell>Environment</TableHeaderCell>
<TableHeaderCell>Last run</TableHeaderCell>
<TableHeaderCell>
<div className="sr-only">Last run status</div>
</TableHeaderCell>
<TableHeaderCell>Created at</TableHeaderCell>
<TableHeaderCell hiddenLabel>Go to page</TableHeaderCell>
</TableRow>
@@ -104,32 +107,40 @@ export default function Page() {
<TableRow key={task.id} className="group">
<TableCell to={path}>{task.slug}</TableCell>
<TableCell to={path}>
<TaskPath
filePath={task.filePath}
functionName={`${task.exportName}()`}
<TaskFunctionName
functionName={task.exportName}
variant="extra-small"
/>
</TableCell>
<TableCell to={path}>{task.filePath}</TableCell>
<TableCell to={path}>
<EnvironmentLabel
environment={task.environment}
userName={usernameForEnv}
/>
</TableCell>
<TableCell to={path}>
{task.latestRun ? (
<div
className={cn(
"flex items-center gap-2",
classForTaskAttemptStatus(task.latestRun.status)
classForTaskRunStatus(task.latestRun.status)
)}
>
<DateTime date={task.latestRun.updatedAt} />
<TaskRunStatus status={task.latestRun.status} />
<DateTime date={task.latestRun.createdAt} />
</div>
) : (
"Never run"
)}
</TableCell>
<TableCell to={path}>
{task.latestRun ? (
<TaskRunStatusCombo status={task.latestRun.status} />
) : (
""
)}
</TableCell>
<TableCell to={path}>
<DateTime date={task.createdAt} />
</TableCell>
@@ -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 "";
@@ -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" && (
<Property label="Status">
<TaskRunStatus
<TaskRunAttemptStatusCombo
status={
event.isCancelled
? "CANCELED"
@@ -3,7 +3,6 @@ import {
ChevronRightIcon,
MagnifyingGlassMinusIcon,
MagnifyingGlassPlusIcon,
NoSymbolIcon,
} from "@heroicons/react/20/solid";
import { Link, Outlet, useNavigate, useRevalidator } from "@remix-run/react";
import { LoaderFunctionArgs } from "@remix-run/server-runtime";
@@ -27,7 +26,6 @@ import { Slider } from "~/components/primitives/Slider";
import { Switch } from "~/components/primitives/Switch";
import * as Timeline from "~/components/primitives/Timeline";
import { TreeView, useTree } from "~/components/primitives/TreeView/TreeView";
import { LiveCountUp, LiveTimer } from "~/components/runs/v3/LiveTimer";
import { RunIcon } from "~/components/runs/v3/RunIcon";
import { SpanTitle, eventBackgroundClassName } from "~/components/runs/v3/SpanTitle";
import { TaskRunStatusIcon, runStatusClassNameColor } from "~/components/runs/v3/TaskRunStatus";
@@ -239,6 +237,9 @@ function TasksTreeView({
},
});
const minTimelineWidth = initialTimelineDimensions?.width ?? 300;
const maxTimelineWidth = minTimelineWidth * 10;
return (
<div className="grid h-full grid-rows-[2.5rem_1fr] overflow-hidden">
<div className="mx-3 flex items-center justify-between gap-2 border-b border-grid-dimmed">
@@ -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 */}
<CurrentTimeIndicator totalDuration={totalDuration} />
@@ -568,14 +569,14 @@ function NodeStatusIcon({ node }: { node: RunEvent }) {
}
if (node.data.isError) {
return <TaskRunStatusIcon status="FAILED" className={cn("size-4")} />;
return <TaskRunStatusIcon status="COMPLETED_WITH_ERRORS" className={cn("size-4")} />;
}
if (node.data.isPartial) {
return <TaskRunStatusIcon status={"EXECUTING"} className={cn("size-4")} />;
}
return <TaskRunStatusIcon status="COMPLETED" className={cn("size-4")} />;
return <TaskRunStatusIcon status="COMPLETED_SUCCESSFULLY" className={cn("size-4")} />;
}
function TaskLine({ isError, isSelected }: { isError: boolean; isSelected: boolean }) {
@@ -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() {
</Paragraph>
<div className="flex items-center gap-1 text-xs text-text-dimmed">
<div>Run #{run.number}</div>
<TaskRunStatus status={run.status} />
<TaskRunStatusCombo status={run.status} />
</div>
</div>
</button>