Show a table of Task retries if there were some

This commit is contained in:
Matt Aitken
2023-06-20 11:30:07 +01:00
parent 969a6a1f2c
commit 622dd6aba4
3 changed files with 143 additions and 0 deletions
@@ -63,6 +63,18 @@ export class TaskDetailsPresenter {
completedAt: true,
style: true,
parentId: true,
attempts: {
select: {
number: true,
status: true,
error: true,
runAt: true,
updatedAt: true,
},
orderBy: {
number: "asc",
},
},
},
where: {
id,
@@ -0,0 +1,90 @@
import {
CheckCircleIcon,
ClockIcon,
XCircleIcon,
} from "@heroicons/react/24/solid";
import { TaskAttemptStatus } from "@trigger.dev/database";
import { Paragraph } from "~/components/primitives/Paragraph";
import { Spinner } from "~/components/primitives/Spinner";
import { cn } from "~/utils/cn";
type TaskAttemptStatusProps = {
status: TaskAttemptStatus;
className?: string;
};
export function TaskAttemptStatusLabel({
status,
}: {
status: TaskAttemptStatus;
}) {
return (
<span className="inline-flex items-center gap-1">
<TaskAttemptStatusIcon status={status} className="h-4 w-4" />
<Paragraph
variant="small"
className={taskAttemptStatusClassNameColor(status)}
>
{taskAttemptStatusTitle(status)}
</Paragraph>
</span>
);
}
export function TaskAttemptStatusIcon({
status,
className,
}: TaskAttemptStatusProps) {
switch (status) {
case "COMPLETED":
return (
<CheckCircleIcon
className={cn(taskAttemptStatusClassNameColor(status), className)}
/>
);
case "PENDING":
return (
<ClockIcon
className={cn(taskAttemptStatusClassNameColor(status), className)}
/>
);
case "STARTED":
return (
<Spinner
className={cn(taskAttemptStatusClassNameColor(status), className)}
/>
);
case "ERRORED":
return (
<XCircleIcon
className={cn(taskAttemptStatusClassNameColor(status), className)}
/>
);
}
}
function taskAttemptStatusClassNameColor(status: TaskAttemptStatus): string {
switch (status) {
case "COMPLETED":
return "text-green-500";
case "PENDING":
return "text-slate-500";
case "STARTED":
return "text-blue-500";
case "ERRORED":
return "text-rose-500";
}
}
function taskAttemptStatusTitle(status: TaskAttemptStatus): string {
switch (status) {
case "COMPLETED":
return "Complete";
case "PENDING":
return "Scheduled";
case "STARTED":
return "Running";
case "ERRORED":
return "Error";
}
}
@@ -23,6 +23,15 @@ import {
} from "../_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.runs.$runParam/RunCard";
import { TaskStatusIcon } from "../_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.runs.$runParam/TaskStatus";
import { sensitiveDataReplacer } from "~/services/logger";
import {
Table,
TableBody,
TableCell,
TableHeader,
TableHeaderCell,
TableRow,
} from "~/components/primitives/Table";
import { TaskAttemptStatusLabel } from "./TaskAttemptStatus";
export const loader = async ({ request, params }: LoaderArgs) => {
const userId = await requireUserId(request);
@@ -63,6 +72,7 @@ export default function Page() {
properties,
output,
style,
attempts,
} = task;
return (
@@ -132,6 +142,37 @@ export default function Page() {
<RunPanelProperties properties={properties} layout="vertical" />
</div>
)}
{attempts.length > 0 && (
<div className="mt-4 flex flex-col gap-2">
<Header3>Retries</Header3>
<Table>
<TableHeader>
<TableHeaderCell>Attempt</TableHeaderCell>
<TableHeaderCell>Status</TableHeaderCell>
<TableHeaderCell>Date</TableHeaderCell>
<TableHeaderCell>Error</TableHeaderCell>
</TableHeader>
<TableBody>
{attempts.map((attempt) => (
<TableRow>
<TableCell>{attempt.number}</TableCell>
<TableCell>
<TaskAttemptStatusLabel status={attempt.status} />
</TableCell>
<TableCell>
{attempt.status === "PENDING" && attempt.runAt
? formatDateTime(attempt.runAt, "long")
: formatDateTime(attempt.updatedAt, "long")}
</TableCell>
<TableCell>{attempt.error}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
)}
<div className="mt-4 flex flex-col gap-2">
<Header3>Input</Header3>
{params ? (