Skip to content

Commit f5317b7

Browse files
committed
Added warm start markers to the Run page and inspector
1 parent 285ad9a commit f5317b7

File tree

3 files changed

+75
-25
lines changed
  • apps/webapp/app
    • presenters/v3
    • routes
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam
      • resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam

3 files changed

+75
-25
lines changed

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

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
isWaitpointOutputTimeout,
33
type MachinePresetName,
44
prettyPrintPacket,
5+
SemanticInternalAttributes,
56
TaskRunError,
67
} from "@trigger.dev/core/v3";
78
import { getMaxDuration } from "@trigger.dev/core/v3/isomorphic";
@@ -455,7 +456,7 @@ export class SpanPresenter extends BasePresenter {
455456
};
456457

457458
switch (span.entity.type) {
458-
case "waitpoint":
459+
case "waitpoint": {
459460
if (!span.entity.id) {
460461
logger.error(`SpanPresenter: No waitpoint id`, {
461462
spanId,
@@ -486,9 +487,29 @@ export class SpanPresenter extends BasePresenter {
486487
object: waitpoint,
487488
},
488489
};
489-
490+
}
491+
case "attempt": {
492+
return {
493+
...data,
494+
entity: {
495+
type: "attempt" as const,
496+
object: {
497+
isWarmStart: isWarmStart(span.properties),
498+
},
499+
},
500+
};
501+
}
490502
default:
491503
return { ...data, entity: null };
492504
}
493505
}
494506
}
507+
508+
function isWarmStart(
509+
attributes: string | number | boolean | Record<string, unknown> | null | undefined
510+
): boolean | undefined {
511+
if (!attributes || typeof attributes !== "object") return undefined;
512+
const attribute = attributes[SemanticInternalAttributes.WARM_START];
513+
if (typeof attribute !== "boolean") return undefined;
514+
return attribute;
515+
}

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

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,18 @@ import {
2121
tryCatch,
2222
} from "@trigger.dev/core/v3";
2323
import { type RuntimeEnvironmentType } from "@trigger.dev/database";
24-
import { AnimatePresence, motion } from "framer-motion";
24+
import { motion } from "framer-motion";
2525
import { useCallback, useEffect, useRef, useState } from "react";
2626
import { useHotkeys } from "react-hotkeys-hook";
27-
import { DisconnectedIcon } from "~/assets/icons/ConnectionIcons";
27+
import { redirect } from "remix-typedjson";
2828
import { ShowParentIcon, ShowParentIconSelected } from "~/assets/icons/ShowParentIcon";
2929
import tileBgPath from "~/assets/images/[email protected]";
30-
import {
31-
DevDisconnectedBanner,
32-
useCrossEngineIsConnected,
33-
useDevPresence,
34-
} from "~/components/DevPresence";
30+
import { DevDisconnectedBanner, useCrossEngineIsConnected } from "~/components/DevPresence";
31+
import { WarmStartIconWithTooltip } from "~/components/WarmStarts";
3532
import { AdminDebugTooltip } from "~/components/admin/debugTooltip";
3633
import { PageBody } from "~/components/layout/AppLayout";
3734
import { Badge } from "~/components/primitives/Badge";
3835
import { Button, LinkButton } from "~/components/primitives/Buttons";
39-
import { Callout } from "~/components/primitives/Callout";
40-
import { ClipboardField } from "~/components/primitives/ClipboardField";
4136
import { DateTimeShort } from "~/components/primitives/DateTime";
4237
import { Dialog, DialogTrigger } from "~/components/primitives/Dialog";
4338
import { Header3 } from "~/components/primitives/Headers";
@@ -100,8 +95,6 @@ import {
10095
} from "~/utils/pathBuilder";
10196
import { useCurrentPlan } from "../_app.orgs.$organizationSlug/route";
10297
import { SpanView } from "../resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route";
103-
import { redirectWithErrorMessage } from "~/models/message.server";
104-
import { redirect } from "remix-typedjson";
10598

10699
const resizableSettings = {
107100
parent: {
@@ -1045,7 +1038,13 @@ function NodeText({ node }: { node: TraceEvent }) {
10451038

10461039
function NodeStatusIcon({ node }: { node: TraceEvent }) {
10471040
if (node.data.level !== "TRACE") return null;
1048-
if (node.data.style.variant !== "primary") return null;
1041+
if (!node.data.style.variant) return null;
1042+
1043+
if (node.data.style.variant === "warm") {
1044+
return <WarmStartIconWithTooltip isWarmStart={true} className="size-4" />;
1045+
} else if (node.data.style.variant === "cold") {
1046+
return <WarmStartIconWithTooltip isWarmStart={false} className="size-4" />;
1047+
}
10491048

10501049
if (node.data.isCancelled) {
10511050
return (

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

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import {
44
EnvelopeIcon,
55
QueueListIcon,
66
} from "@heroicons/react/20/solid";
7-
import { Link } from "@remix-run/react";
87
import { type LoaderFunctionArgs } from "@remix-run/server-runtime";
98
import {
109
formatDurationMilliseconds,
1110
type TaskRunError,
1211
taskRunErrorEnhancer,
1312
} from "@trigger.dev/core/v3";
13+
import { assertNever } from "assert-never";
1414
import { useEffect } from "react";
1515
import { typedjson, useTypedFetcher } from "remix-typedjson";
1616
import { ExitIcon } from "~/assets/icons/ExitIcon";
@@ -37,20 +37,23 @@ import { TabButton, TabContainer } from "~/components/primitives/Tabs";
3737
import { TextLink } from "~/components/primitives/TextLink";
3838
import { InfoIconTooltip, SimpleTooltip } from "~/components/primitives/Tooltip";
3939
import { RunTimeline, RunTimelineEvent, SpanTimeline } from "~/components/run/RunTimeline";
40+
import { PacketDisplay } from "~/components/runs/v3/PacketDisplay";
4041
import { RunIcon } from "~/components/runs/v3/RunIcon";
4142
import { RunTag } from "~/components/runs/v3/RunTag";
4243
import { SpanEvents } from "~/components/runs/v3/SpanEvents";
4344
import { SpanTitle } from "~/components/runs/v3/SpanTitle";
4445
import { TaskRunAttemptStatusCombo } from "~/components/runs/v3/TaskRunAttemptStatus";
4546
import { TaskRunStatusCombo, TaskRunStatusReason } from "~/components/runs/v3/TaskRunStatus";
47+
import { WaitpointDetailTable } from "~/components/runs/v3/WaitpointDetails";
48+
import { WarmStartCombo } from "~/components/WarmStarts";
49+
import { useEnvironment } from "~/hooks/useEnvironment";
4650
import { useOrganization } from "~/hooks/useOrganizations";
4751
import { useProject } from "~/hooks/useProject";
4852
import { useSearchParams } from "~/hooks/useSearchParam";
4953
import { useHasAdminAccess } from "~/hooks/useUser";
5054
import { redirectWithErrorMessage } from "~/models/message.server";
5155
import { type Span, SpanPresenter, type SpanRun } from "~/presenters/v3/SpanPresenter.server";
5256
import { logger } from "~/services/logger.server";
53-
import { requireUserId } from "~/services/session.server";
5457
import { cn } from "~/utils/cn";
5558
import { formatCurrencyAccurate } from "~/utils/numberFormatter";
5659
import {
@@ -63,15 +66,8 @@ import {
6366
v3SchedulePath,
6467
v3SpanParamsSchema,
6568
} from "~/utils/pathBuilder";
66-
import {
67-
CompleteWaitpointForm,
68-
ForceTimeout,
69-
} from "../resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.$waitpointFriendlyId.complete/route";
70-
import { useEnvironment } from "~/hooks/useEnvironment";
71-
import { WaitpointStatusCombo } from "~/components/runs/v3/WaitpointStatus";
72-
import { PacketDisplay } from "~/components/runs/v3/PacketDisplay";
73-
import { WaitpointDetailTable } from "~/components/runs/v3/WaitpointDetails";
7469
import { createTimelineSpanEventsFromSpanEvents } from "~/utils/timelineSpanEvents";
70+
import { CompleteWaitpointForm } from "../resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.$waitpointFriendlyId.complete/route";
7571

7672
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
7773
const { projectParam, organizationSlug, envParam, runParam, spanParam } =
@@ -935,6 +931,40 @@ function SpanEntity({ span }: { span: Span }) {
935931
}
936932

937933
switch (span.entity.type) {
934+
case "attempt": {
935+
return (
936+
<div className="flex flex-col gap-4 p-3">
937+
<div className="border-b border-grid-bright pb-3">
938+
<TaskRunAttemptStatusCombo
939+
status={
940+
span.isCancelled
941+
? "CANCELED"
942+
: span.isError
943+
? "FAILED"
944+
: span.isPartial
945+
? "EXECUTING"
946+
: "COMPLETED"
947+
}
948+
className="text-sm"
949+
/>
950+
</div>
951+
<SpanTimeline
952+
startTime={new Date(span.startTime)}
953+
duration={span.duration}
954+
inProgress={span.isPartial}
955+
isError={span.isError}
956+
events={createTimelineSpanEventsFromSpanEvents(span.events, isAdmin)}
957+
/>
958+
{span.entity.object.isWarmStart !== undefined ? (
959+
<WarmStartCombo
960+
isWarmStart={span.entity.object.isWarmStart}
961+
showTooltip
962+
className="mt-3"
963+
/>
964+
) : null}
965+
</div>
966+
);
967+
}
938968
case "waitpoint": {
939969
return (
940970
<div className="grid h-full grid-rows-[1fr_auto]">
@@ -957,7 +987,7 @@ function SpanEntity({ span }: { span: Span }) {
957987
);
958988
}
959989
default: {
960-
return <Paragraph variant="small">No span for {span.entity.type}</Paragraph>;
990+
assertNever(span.entity);
961991
}
962992
}
963993
}

0 commit comments

Comments
 (0)