Run page turned into components so it can be shared
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import { CodeBlock } from "~/components/code/CodeBlock";
|
||||
import { DateTime } from "~/components/primitives/DateTime";
|
||||
import { Paragraph } from "~/components/primitives/Paragraph";
|
||||
import { RunStatusIcon, RunStatusLabel } from "~/components/runs/RunStatuses";
|
||||
import { useRun } from "~/hooks/useRun";
|
||||
import { formatDuration } from "~/utils";
|
||||
import {
|
||||
RunPanel,
|
||||
RunPanelBody,
|
||||
RunPanelDivider,
|
||||
RunPanelError,
|
||||
RunPanelHeader,
|
||||
RunPanelIconProperty,
|
||||
RunPanelIconSection,
|
||||
} from "./RunCard";
|
||||
|
||||
export function RunCompletedDetail() {
|
||||
const run = useRun();
|
||||
|
||||
return (
|
||||
<RunPanel>
|
||||
<RunPanelHeader
|
||||
icon={<RunStatusIcon status={run.status} className={"h-5 w-5"} />}
|
||||
title={
|
||||
<Paragraph variant="small/bright">
|
||||
<RunStatusLabel status={run.status} />
|
||||
</Paragraph>
|
||||
}
|
||||
/>
|
||||
<RunPanelBody>
|
||||
<RunPanelIconSection>
|
||||
{run.startedAt && (
|
||||
<RunPanelIconProperty
|
||||
icon="calendar"
|
||||
label="Started at"
|
||||
value={<DateTime date={run.startedAt} />}
|
||||
/>
|
||||
)}
|
||||
{run.completedAt && (
|
||||
<RunPanelIconProperty
|
||||
icon="flag"
|
||||
label="Finished at"
|
||||
value={<DateTime date={run.completedAt} />}
|
||||
/>
|
||||
)}
|
||||
{run.startedAt && run.completedAt && (
|
||||
<RunPanelIconProperty
|
||||
icon="clock"
|
||||
label="Total duration"
|
||||
value={formatDuration(run.startedAt, run.completedAt, {
|
||||
style: "long",
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</RunPanelIconSection>
|
||||
<RunPanelDivider />
|
||||
{run.error && (
|
||||
<RunPanelError
|
||||
text={run.error.message}
|
||||
stackTrace={run.error.stack}
|
||||
/>
|
||||
)}
|
||||
{run.output ? (
|
||||
<CodeBlock language="json" code={run.output} />
|
||||
) : (
|
||||
run.output === null && (
|
||||
<Paragraph variant="small">This run returned nothing</Paragraph>
|
||||
)
|
||||
)}
|
||||
</RunPanelBody>
|
||||
</RunPanel>
|
||||
);
|
||||
}
|
||||
@@ -169,15 +169,7 @@ export function RunOverview({
|
||||
selected={selectedId === "trigger"}
|
||||
onClick={() => navigate(runTriggerPath(paths.run))}
|
||||
>
|
||||
<RunPanelHeader
|
||||
icon={<BoltIcon className="h-5 w-5 text-orange-500" />}
|
||||
title={
|
||||
<RunPanelIconTitle
|
||||
icon={trigger.icon}
|
||||
title={trigger.title}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<RunPanelHeader icon={trigger.icon} title={trigger.title} />
|
||||
<RunPanelBody>
|
||||
<RunPanelProperties
|
||||
properties={[
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
import { DetailedTask } from "~/presenters/TaskDetailsPresenter.server";
|
||||
import {
|
||||
RunPanel,
|
||||
RunPanelBody,
|
||||
RunPanelDescription,
|
||||
RunPanelDivider,
|
||||
RunPanelHeader,
|
||||
RunPanelIconProperty,
|
||||
RunPanelIconSection,
|
||||
RunPanelIconTitle,
|
||||
RunPanelProperties,
|
||||
UpdatingDelay,
|
||||
UpdatingDuration,
|
||||
} from "./RunCard";
|
||||
import { sensitiveDataReplacer } from "~/services/sensitiveDataReplacer";
|
||||
import { formatDuration } from "~/utils";
|
||||
import { cn } from "~/utils/cn";
|
||||
import { CodeBlock } from "../code/CodeBlock";
|
||||
import { DateTime } from "../primitives/DateTime";
|
||||
import { Header3 } from "../primitives/Headers";
|
||||
import { Paragraph } from "../primitives/Paragraph";
|
||||
import {
|
||||
TableHeader,
|
||||
TableRow,
|
||||
TableHeaderCell,
|
||||
TableBody,
|
||||
TableCell,
|
||||
Table,
|
||||
} from "../primitives/Table";
|
||||
import { TaskAttemptStatusLabel } from "./TaskAttemptStatus";
|
||||
import { TaskStatusIcon } from "./TaskStatus";
|
||||
|
||||
export function TaskDetail({ task }: { task: DetailedTask }) {
|
||||
const {
|
||||
name,
|
||||
description,
|
||||
icon,
|
||||
startedAt,
|
||||
completedAt,
|
||||
status,
|
||||
delayUntil,
|
||||
params,
|
||||
properties,
|
||||
output,
|
||||
style,
|
||||
attempts,
|
||||
} = task;
|
||||
|
||||
return (
|
||||
<RunPanel selected={false}>
|
||||
<RunPanelHeader
|
||||
icon={
|
||||
<TaskStatusIcon
|
||||
status={status}
|
||||
minimal={true}
|
||||
className={cn("h-5 w-5")}
|
||||
/>
|
||||
}
|
||||
title={<RunPanelIconTitle icon={icon} title={name} />}
|
||||
accessory={
|
||||
<Paragraph variant="extra-small">
|
||||
<UpdatingDuration
|
||||
start={startedAt ?? undefined}
|
||||
end={completedAt ?? undefined}
|
||||
/>
|
||||
</Paragraph>
|
||||
}
|
||||
/>
|
||||
<RunPanelBody>
|
||||
<RunPanelIconSection>
|
||||
{startedAt && (
|
||||
<RunPanelIconProperty
|
||||
icon="calendar"
|
||||
label="Started at"
|
||||
value={<DateTime date={startedAt} />}
|
||||
/>
|
||||
)}
|
||||
{completedAt && (
|
||||
<RunPanelIconProperty
|
||||
icon="flag"
|
||||
label="Finished at"
|
||||
value={<DateTime date={completedAt} />}
|
||||
/>
|
||||
)}
|
||||
{delayUntil && !completedAt && (
|
||||
<>
|
||||
<RunPanelIconProperty
|
||||
icon="flag"
|
||||
label="Continues at"
|
||||
value={<DateTime date={delayUntil} />}
|
||||
/>
|
||||
<UpdatingDelay delayUntil={delayUntil} />
|
||||
</>
|
||||
)}
|
||||
{delayUntil && completedAt && (
|
||||
<RunPanelIconProperty
|
||||
icon="clock"
|
||||
label="Delay duration"
|
||||
value={formatDuration(startedAt, delayUntil, {
|
||||
style: "long",
|
||||
maxDecimalPoints: 0,
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</RunPanelIconSection>
|
||||
<RunPanelDivider />
|
||||
{description && (
|
||||
<RunPanelDescription text={description} variant={style?.variant} />
|
||||
)}
|
||||
{properties.length > 0 && (
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
<Header3>Properties</Header3>
|
||||
<RunPanelProperties properties={properties} layout="horizontal" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{attempts.length > 1 && (
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
<Header3>Retries</Header3>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHeaderCell>Attempt</TableHeaderCell>
|
||||
<TableHeaderCell>Status</TableHeaderCell>
|
||||
<TableHeaderCell>Date</TableHeaderCell>
|
||||
<TableHeaderCell>Error</TableHeaderCell>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{attempts.map((attempt) => (
|
||||
<TableRow key={attempt.number}>
|
||||
<TableCell>{attempt.number}</TableCell>
|
||||
<TableCell>
|
||||
<TaskAttemptStatusLabel status={attempt.status} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<DateTime
|
||||
date={
|
||||
attempt.status === "PENDING" && attempt.runAt
|
||||
? attempt.runAt
|
||||
: attempt.updatedAt
|
||||
}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>{attempt.error}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
<Header3>Input</Header3>
|
||||
{params ? (
|
||||
<CodeBlock
|
||||
code={JSON.stringify(params, sensitiveDataReplacer, 2)}
|
||||
maxLines={35}
|
||||
/>
|
||||
) : (
|
||||
<Paragraph variant="small">No input</Paragraph>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
<Header3>Output</Header3>
|
||||
{output ? (
|
||||
<CodeBlock code={JSON.stringify(output, null, 2)} />
|
||||
) : (
|
||||
<Paragraph variant="small">No output</Paragraph>
|
||||
)}
|
||||
</div>
|
||||
</RunPanelBody>
|
||||
</RunPanel>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { DetailedEvent } from "~/presenters/TriggerDetailsPresenter.server";
|
||||
import { CodeBlock } from "../code/CodeBlock";
|
||||
import { DateTime } from "../primitives/DateTime";
|
||||
import { Header3 } from "../primitives/Headers";
|
||||
import {
|
||||
RunPanel,
|
||||
RunPanelBody,
|
||||
RunPanelDivider,
|
||||
RunPanelHeader,
|
||||
RunPanelIconProperty,
|
||||
RunPanelIconSection,
|
||||
RunPanelProperties,
|
||||
} from "./RunCard";
|
||||
import { DisplayProperty } from "@trigger.dev/internal";
|
||||
|
||||
export function TriggerDetail({
|
||||
trigger,
|
||||
event,
|
||||
properties,
|
||||
}: {
|
||||
trigger: DetailedEvent;
|
||||
event: {
|
||||
title: string;
|
||||
icon: string;
|
||||
};
|
||||
properties: DisplayProperty[];
|
||||
}) {
|
||||
const { id, name, payload, timestamp, deliveredAt } = trigger;
|
||||
|
||||
return (
|
||||
<RunPanel selected={false}>
|
||||
<RunPanelHeader icon={event.icon} title={event.title} />
|
||||
<RunPanelBody>
|
||||
<RunPanelIconSection>
|
||||
<RunPanelIconProperty
|
||||
icon="calendar"
|
||||
label="Created"
|
||||
value={<DateTime date={timestamp} />}
|
||||
/>
|
||||
{deliveredAt && (
|
||||
<RunPanelIconProperty
|
||||
icon="flag"
|
||||
label="Finished at"
|
||||
value={<DateTime date={deliveredAt} />}
|
||||
/>
|
||||
)}
|
||||
<RunPanelIconProperty icon="id" label="Event name" value={name} />
|
||||
</RunPanelIconSection>
|
||||
<RunPanelDivider />
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
{properties.length > 0 && (
|
||||
<div className="mb-2 flex flex-col gap-4">
|
||||
<Header3>Properties</Header3>
|
||||
<RunPanelProperties properties={properties} layout="horizontal" />
|
||||
</div>
|
||||
)}
|
||||
<Header3>Payload</Header3>
|
||||
<CodeBlock code={JSON.stringify(payload, null, 2)} />
|
||||
</div>
|
||||
</RunPanelBody>
|
||||
</RunPanel>
|
||||
);
|
||||
}
|
||||
+2
-7
@@ -1,15 +1,10 @@
|
||||
import { PrismaClient, prisma } from "~/db.server";
|
||||
|
||||
type DetailsProps = {
|
||||
id: string;
|
||||
userId: string;
|
||||
};
|
||||
|
||||
export type DetailedEvent = NonNullable<
|
||||
Awaited<ReturnType<EventDetailsPresenter["call"]>>
|
||||
Awaited<ReturnType<TriggerDetailsPresenter["call"]>>
|
||||
>;
|
||||
|
||||
export class EventDetailsPresenter {
|
||||
export class TriggerDetailsPresenter {
|
||||
#prismaClient: PrismaClient;
|
||||
|
||||
constructor(prismaClient: PrismaClient = prisma) {
|
||||
+2
-70
@@ -1,73 +1,5 @@
|
||||
import { CodeBlock } from "~/components/code/CodeBlock";
|
||||
import { DateTime } from "~/components/primitives/DateTime";
|
||||
import { Paragraph } from "~/components/primitives/Paragraph";
|
||||
import { RunStatusIcon, RunStatusLabel } from "~/components/runs/RunStatuses";
|
||||
import { useRun } from "~/hooks/useRun";
|
||||
import { formatDuration } from "~/utils";
|
||||
import {
|
||||
RunPanel,
|
||||
RunPanelBody,
|
||||
RunPanelDivider,
|
||||
RunPanelError,
|
||||
RunPanelHeader,
|
||||
RunPanelIconProperty,
|
||||
RunPanelIconSection,
|
||||
} from "../../components/run/RunCard";
|
||||
import { RunCompletedDetail } from "~/components/run/RunCompletedDetail";
|
||||
|
||||
export default function RunCompletedPage() {
|
||||
const run = useRun();
|
||||
|
||||
return (
|
||||
<RunPanel>
|
||||
<RunPanelHeader
|
||||
icon={<RunStatusIcon status={run.status} className={"h-5 w-5"} />}
|
||||
title={
|
||||
<Paragraph variant="small/bright">
|
||||
<RunStatusLabel status={run.status} />
|
||||
</Paragraph>
|
||||
}
|
||||
/>
|
||||
<RunPanelBody>
|
||||
<RunPanelIconSection>
|
||||
{run.startedAt && (
|
||||
<RunPanelIconProperty
|
||||
icon="calendar"
|
||||
label="Started at"
|
||||
value={<DateTime date={run.startedAt} />}
|
||||
/>
|
||||
)}
|
||||
{run.completedAt && (
|
||||
<RunPanelIconProperty
|
||||
icon="flag"
|
||||
label="Finished at"
|
||||
value={<DateTime date={run.completedAt} />}
|
||||
/>
|
||||
)}
|
||||
{run.startedAt && run.completedAt && (
|
||||
<RunPanelIconProperty
|
||||
icon="clock"
|
||||
label="Total duration"
|
||||
value={formatDuration(run.startedAt, run.completedAt, {
|
||||
style: "long",
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</RunPanelIconSection>
|
||||
<RunPanelDivider />
|
||||
{run.error && (
|
||||
<RunPanelError
|
||||
text={run.error.message}
|
||||
stackTrace={run.error.stack}
|
||||
/>
|
||||
)}
|
||||
{run.output ? (
|
||||
<CodeBlock language="json" code={run.output} />
|
||||
) : (
|
||||
run.output === null && (
|
||||
<Paragraph variant="small">This run returned nothing</Paragraph>
|
||||
)
|
||||
)}
|
||||
</RunPanelBody>
|
||||
</RunPanel>
|
||||
);
|
||||
return <RunCompletedDetail />;
|
||||
}
|
||||
|
||||
+2
-172
@@ -1,38 +1,9 @@
|
||||
import { LoaderArgs } from "@remix-run/server-runtime";
|
||||
import { typedjson, useTypedLoaderData } from "remix-typedjson";
|
||||
import { CodeBlock } from "~/components/code/CodeBlock";
|
||||
import { DateTime } from "~/components/primitives/DateTime";
|
||||
import { Header3 } from "~/components/primitives/Headers";
|
||||
import { Paragraph } from "~/components/primitives/Paragraph";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHeader,
|
||||
TableHeaderCell,
|
||||
TableRow,
|
||||
} from "~/components/primitives/Table";
|
||||
import { TaskDetail } from "~/components/run/TaskDetail";
|
||||
import { TaskDetailsPresenter } from "~/presenters/TaskDetailsPresenter.server";
|
||||
import { sensitiveDataReplacer } from "~/services/sensitiveDataReplacer";
|
||||
import { requireUserId } from "~/services/session.server";
|
||||
import { formatDuration } from "~/utils";
|
||||
import { cn } from "~/utils/cn";
|
||||
import { TaskParamsSchema } from "~/utils/pathBuilder";
|
||||
import {
|
||||
RunPanel,
|
||||
RunPanelBody,
|
||||
RunPanelDescription,
|
||||
RunPanelDivider,
|
||||
RunPanelHeader,
|
||||
RunPanelIconProperty,
|
||||
RunPanelIconSection,
|
||||
RunPanelIconTitle,
|
||||
RunPanelProperties,
|
||||
UpdatingDelay,
|
||||
UpdatingDuration,
|
||||
} from "../../components/run/RunCard";
|
||||
import { TaskAttemptStatusLabel } from "./TaskAttemptStatus";
|
||||
import { TaskStatusIcon } from "~/components/run/TaskStatus";
|
||||
|
||||
export const loader = async ({ request, params }: LoaderArgs) => {
|
||||
const userId = await requireUserId(request);
|
||||
@@ -57,146 +28,5 @@ export const loader = async ({ request, params }: LoaderArgs) => {
|
||||
|
||||
export default function Page() {
|
||||
const { task } = useTypedLoaderData<typeof loader>();
|
||||
|
||||
const {
|
||||
name,
|
||||
description,
|
||||
icon,
|
||||
startedAt,
|
||||
completedAt,
|
||||
status,
|
||||
delayUntil,
|
||||
params,
|
||||
properties,
|
||||
output,
|
||||
style,
|
||||
attempts,
|
||||
} = task;
|
||||
|
||||
return (
|
||||
<RunPanel selected={false}>
|
||||
<RunPanelHeader
|
||||
icon={
|
||||
<TaskStatusIcon
|
||||
status={status}
|
||||
minimal={true}
|
||||
className={cn("h-5 w-5")}
|
||||
/>
|
||||
}
|
||||
title={<RunPanelIconTitle icon={icon} title={name} />}
|
||||
accessory={
|
||||
<Paragraph variant="extra-small">
|
||||
<UpdatingDuration
|
||||
start={startedAt ?? undefined}
|
||||
end={completedAt ?? undefined}
|
||||
/>
|
||||
</Paragraph>
|
||||
}
|
||||
/>
|
||||
<RunPanelBody>
|
||||
<RunPanelIconSection>
|
||||
{startedAt && (
|
||||
<RunPanelIconProperty
|
||||
icon="calendar"
|
||||
label="Started at"
|
||||
value={<DateTime date={startedAt} />}
|
||||
/>
|
||||
)}
|
||||
{completedAt && (
|
||||
<RunPanelIconProperty
|
||||
icon="flag"
|
||||
label="Finished at"
|
||||
value={<DateTime date={completedAt} />}
|
||||
/>
|
||||
)}
|
||||
{delayUntil && !completedAt && (
|
||||
<>
|
||||
<RunPanelIconProperty
|
||||
icon="flag"
|
||||
label="Continues at"
|
||||
value={<DateTime date={delayUntil} />}
|
||||
/>
|
||||
<UpdatingDelay delayUntil={delayUntil} />
|
||||
</>
|
||||
)}
|
||||
{delayUntil && completedAt && (
|
||||
<RunPanelIconProperty
|
||||
icon="clock"
|
||||
label="Delay duration"
|
||||
value={formatDuration(startedAt, delayUntil, {
|
||||
style: "long",
|
||||
maxDecimalPoints: 0,
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</RunPanelIconSection>
|
||||
<RunPanelDivider />
|
||||
{description && (
|
||||
<RunPanelDescription text={description} variant={style?.variant} />
|
||||
)}
|
||||
{properties.length > 0 && (
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
<Header3>Properties</Header3>
|
||||
<RunPanelProperties properties={properties} layout="horizontal" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{attempts.length > 1 && (
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
<Header3>Retries</Header3>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHeaderCell>Attempt</TableHeaderCell>
|
||||
<TableHeaderCell>Status</TableHeaderCell>
|
||||
<TableHeaderCell>Date</TableHeaderCell>
|
||||
<TableHeaderCell>Error</TableHeaderCell>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{attempts.map((attempt) => (
|
||||
<TableRow key={attempt.number}>
|
||||
<TableCell>{attempt.number}</TableCell>
|
||||
<TableCell>
|
||||
<TaskAttemptStatusLabel status={attempt.status} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<DateTime
|
||||
date={
|
||||
attempt.status === "PENDING" && attempt.runAt
|
||||
? attempt.runAt
|
||||
: attempt.updatedAt
|
||||
}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>{attempt.error}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
<Header3>Input</Header3>
|
||||
{params ? (
|
||||
<CodeBlock
|
||||
code={JSON.stringify(params, sensitiveDataReplacer, 2)}
|
||||
maxLines={35}
|
||||
/>
|
||||
) : (
|
||||
<Paragraph variant="small">No input</Paragraph>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
<Header3>Output</Header3>
|
||||
{output ? (
|
||||
<CodeBlock code={JSON.stringify(output, null, 2)} />
|
||||
) : (
|
||||
<Paragraph variant="small">No output</Paragraph>
|
||||
)}
|
||||
</div>
|
||||
</RunPanelBody>
|
||||
</RunPanel>
|
||||
);
|
||||
return <TaskDetail task={task} />;
|
||||
}
|
||||
|
||||
+12
-54
@@ -1,80 +1,38 @@
|
||||
import { LoaderArgs } from "@remix-run/server-runtime";
|
||||
import { typedjson, useTypedLoaderData } from "remix-typedjson";
|
||||
import { CodeBlock } from "~/components/code/CodeBlock";
|
||||
import { DateTime } from "~/components/primitives/DateTime";
|
||||
import { Header3 } from "~/components/primitives/Headers";
|
||||
import { TriggerDetail } from "~/components/run/TriggerDetail";
|
||||
import { useJob } from "~/hooks/useJob";
|
||||
import { useRun } from "~/hooks/useRun";
|
||||
import { EventDetailsPresenter } from "~/presenters/EventDetailsPresenter.server";
|
||||
import { TriggerDetailsPresenter } from "~/presenters/TriggerDetailsPresenter.server";
|
||||
import { RunParamsSchema } from "~/utils/pathBuilder";
|
||||
import {
|
||||
RunPanel,
|
||||
RunPanelBody,
|
||||
RunPanelDivider,
|
||||
RunPanelHeader,
|
||||
RunPanelIconProperty,
|
||||
RunPanelIconSection,
|
||||
RunPanelProperties,
|
||||
} from "../../components/run/RunCard";
|
||||
|
||||
export const loader = async ({ request, params }: LoaderArgs) => {
|
||||
const { runParam } = RunParamsSchema.parse(params);
|
||||
|
||||
const presenter = new EventDetailsPresenter();
|
||||
const event = await presenter.call(runParam);
|
||||
const presenter = new TriggerDetailsPresenter();
|
||||
const trigger = await presenter.call(runParam);
|
||||
|
||||
if (!event) {
|
||||
if (!trigger) {
|
||||
throw new Response(null, {
|
||||
status: 404,
|
||||
});
|
||||
}
|
||||
|
||||
return typedjson({
|
||||
event,
|
||||
trigger,
|
||||
});
|
||||
};
|
||||
|
||||
export default function Page() {
|
||||
const { event } = useTypedLoaderData<typeof loader>();
|
||||
const { trigger } = useTypedLoaderData<typeof loader>();
|
||||
const job = useJob();
|
||||
const run = useRun();
|
||||
|
||||
const { id, name, payload, timestamp, deliveredAt } = event;
|
||||
|
||||
return (
|
||||
<RunPanel selected={false}>
|
||||
<RunPanelHeader icon={job.event.icon} title={job.event.title} />
|
||||
<RunPanelBody>
|
||||
<RunPanelIconSection>
|
||||
<RunPanelIconProperty
|
||||
icon="calendar"
|
||||
label="Created"
|
||||
value={<DateTime date={timestamp} />}
|
||||
/>
|
||||
{deliveredAt && (
|
||||
<RunPanelIconProperty
|
||||
icon="flag"
|
||||
label="Finished at"
|
||||
value={<DateTime date={deliveredAt} />}
|
||||
/>
|
||||
)}
|
||||
<RunPanelIconProperty icon="id" label="Event name" value={name} />
|
||||
</RunPanelIconSection>
|
||||
<RunPanelDivider />
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
{run.properties.length > 0 && (
|
||||
<div className="mb-2 flex flex-col gap-4">
|
||||
<Header3>Properties</Header3>
|
||||
<RunPanelProperties
|
||||
properties={run.properties}
|
||||
layout="horizontal"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<Header3>Payload</Header3>
|
||||
<CodeBlock code={JSON.stringify(payload, null, 2)} />
|
||||
</div>
|
||||
</RunPanelBody>
|
||||
</RunPanel>
|
||||
<TriggerDetail
|
||||
trigger={trigger}
|
||||
event={job.event}
|
||||
properties={run.properties}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user