diff --git a/apps/webapp/app/components/runs/v3/InspectorTimeline.tsx b/apps/webapp/app/components/runs/v3/InspectorTimeline.tsx
new file mode 100644
index 000000000..1d574ff6a
--- /dev/null
+++ b/apps/webapp/app/components/runs/v3/InspectorTimeline.tsx
@@ -0,0 +1,63 @@
+import { ReactNode } from "react";
+import { cn } from "~/utils/cn";
+
+type RunTimelineItemProps = {
+ title: ReactNode;
+ subtitle?: ReactNode;
+ state: "complete" | "error";
+};
+
+export function RunTimelineEvent({ title, subtitle, state }: RunTimelineItemProps) {
+ return (
+
+
+
+ {title}
+ {subtitle ? {subtitle} : null}
+
+
+ );
+}
+
+type RunTimelineLineProps = {
+ title: ReactNode;
+ state: "complete" | "delayed" | "inprogress";
+};
+
+export function RunTimelineLine({ title, state }: RunTimelineLineProps) {
+ return (
+
+ );
+}
diff --git a/apps/webapp/app/components/runs/v3/RunInspector.tsx b/apps/webapp/app/components/runs/v3/RunInspector.tsx
index ea3870dbf..291ef58a1 100644
--- a/apps/webapp/app/components/runs/v3/RunInspector.tsx
+++ b/apps/webapp/app/components/runs/v3/RunInspector.tsx
@@ -1,11 +1,8 @@
import { CheckIcon, ClockIcon, CloudArrowDownIcon, QueueListIcon } from "@heroicons/react/20/solid";
-import {
- formatDuration,
- formatDurationMilliseconds,
- nanosecondsToMilliseconds,
- TaskRunError,
-} from "@trigger.dev/core/v3";
-import { ReactNode, useEffect } from "react";
+import { Link } from "@remix-run/react";
+import { formatDuration, formatDurationMilliseconds, TaskRunError } from "@trigger.dev/core/v3";
+import { useEffect } from "react";
+import { useTypedFetcher } from "remix-typedjson";
import { ExitIcon } from "~/assets/icons/ExitIcon";
import { CodeBlock } from "~/components/code/CodeBlock";
import { EnvironmentLabel } from "~/components/environments/EnvironmentLabel";
@@ -25,6 +22,7 @@ import { useOrganization } from "~/hooks/useOrganizations";
import { useProject } from "~/hooks/useProject";
import { useSearchParams } from "~/hooks/useSearchParam";
import { RawRun } from "~/hooks/useSyncTraceRuns";
+import { loader } from "~/routes/resources.runs.$runParam";
import { cn } from "~/utils/cn";
import { formatCurrencyAccurate } from "~/utils/numberFormatter";
import {
@@ -35,15 +33,12 @@ import {
v3SchedulePath,
v3TraceSpanPath,
} from "~/utils/pathBuilder";
+import { TraceSpan } from "~/utils/taskEvent";
import { SpanLink } from "~/v3/eventRepository.server";
import { isFinalRunStatus } from "~/v3/taskStatus";
-import { TaskRunStatusCombo } from "./TaskRunStatus";
-import { useTypedFetcher } from "remix-typedjson";
-import { RunInspectorData } from "~/routes/resources.runs.$runParam";
-import { loader } from "~/routes/resources.runs.$runParam";
-import { Link } from "@remix-run/react";
+import { RunTimelineEvent, RunTimelineLine } from "./InspectorTimeline";
import { RunTag } from "./RunTag";
-import { TraceSpan } from "~/utils/taskEvent";
+import { TaskRunStatusCombo } from "./TaskRunStatus";
/**
* The RunInspector displays live information about a run.
@@ -529,67 +524,6 @@ function RunTimeline({ run }: { run: RawRun }) {
);
}
-type RunTimelineItemProps = {
- title: ReactNode;
- subtitle?: ReactNode;
- state: "complete" | "error";
-};
-
-function RunTimelineEvent({ title, subtitle, state }: RunTimelineItemProps) {
- return (
-
-
-
- {title}
- {subtitle ? {subtitle} : null}
-
-
- );
-}
-
-type RunTimelineLineProps = {
- title: ReactNode;
- state: "complete" | "delayed" | "inprogress";
-};
-
-function RunTimelineLine({ title, state }: RunTimelineLineProps) {
- return (
-
- );
-}
-
function RunError({ error }: { error: TaskRunError }) {
switch (error.type) {
case "STRING_ERROR":
@@ -673,91 +607,6 @@ function PacketDisplay({
}
}
-type TimelineProps = {
- startTime: Date;
- duration: number;
- inProgress: boolean;
- isError: boolean;
-};
-
-type TimelineState = "error" | "pending" | "complete";
-
-function SpanTimeline({ startTime, duration, inProgress, isError }: TimelineProps) {
- const state = isError ? "error" : inProgress ? "pending" : "complete";
- return (
- <>
-
- }
- state="complete"
- />
- {state === "pending" ? (
-
-
-
-
-
-
- }
- state={"inprogress"}
- />
- ) : (
- <>
-
-
- }
- state={isError ? "error" : "complete"}
- />
- >
- )}
-
- >
- );
-}
-
-function VerticalBar({ state }: { state: TimelineState }) {
- return ;
-}
-
-function DottedLine() {
- return (
-
- );
-}
-
-function classNameForState(state: TimelineState) {
- switch (state) {
- case "pending": {
- return "bg-pending";
- }
- case "complete": {
- return "bg-success";
- }
- case "error": {
- return "bg-error";
- }
- }
-}
-
function SpanLinkElement({ link }: { link: SpanLink }) {
const organization = useOrganization();
const project = useProject();
diff --git a/apps/webapp/app/components/runs/v3/SpanInspector.tsx b/apps/webapp/app/components/runs/v3/SpanInspector.tsx
index eb0cd79ab..4b6ac7979 100644
--- a/apps/webapp/app/components/runs/v3/SpanInspector.tsx
+++ b/apps/webapp/app/components/runs/v3/SpanInspector.tsx
@@ -1,16 +1,12 @@
-import { formatDuration, nanosecondsToMilliseconds } from "@trigger.dev/core/v3";
-import { ReactNode } from "react";
import { ExitIcon } from "~/assets/icons/ExitIcon";
import { CodeBlock } from "~/components/code/CodeBlock";
import { Button } from "~/components/primitives/Buttons";
import { DateTimeAccurate } from "~/components/primitives/DateTime";
import { Header2 } from "~/components/primitives/Headers";
import * as Property from "~/components/primitives/PropertyTable";
-import { Spinner } from "~/components/primitives/Spinner";
import { TabButton, TabContainer } from "~/components/primitives/Tabs";
import { TextLink } from "~/components/primitives/TextLink";
import { InfoIconTooltip, SimpleTooltip } from "~/components/primitives/Tooltip";
-import { LiveTimer } from "~/components/runs/v3/LiveTimer";
import { RunIcon } from "~/components/runs/v3/RunIcon";
import { SpanEvents } from "~/components/runs/v3/SpanEvents";
import { SpanTitle } from "~/components/runs/v3/SpanTitle";
@@ -22,6 +18,10 @@ import { cn } from "~/utils/cn";
import { v3RunPath, v3RunsPath, v3TraceSpanPath } from "~/utils/pathBuilder";
import { TraceSpan } from "~/utils/taskEvent";
import { SpanLink } from "~/v3/eventRepository.server";
+import { RunTimelineEvent, RunTimelineLine } from "./InspectorTimeline";
+import { Spinner } from "~/components/primitives/Spinner";
+import { LiveTimer } from "./LiveTimer";
+import { formatDuration, nanosecondsToMilliseconds } from "@trigger.dev/core/v3";
export function SpanInspector({
span,
@@ -234,67 +234,6 @@ export function SpanInspector({
);
}
-type RunTimelineItemProps = {
- title: ReactNode;
- subtitle?: ReactNode;
- state: "complete" | "error";
-};
-
-function RunTimelineEvent({ title, subtitle, state }: RunTimelineItemProps) {
- return (
-
-
-
- {title}
- {subtitle ? {subtitle} : null}
-
-
- );
-}
-
-type RunTimelineLineProps = {
- title: ReactNode;
- state: "complete" | "delayed" | "inprogress";
-};
-
-function RunTimelineLine({ title, state }: RunTimelineLineProps) {
- return (
-
- );
-}
-
type TimelineProps = {
startTime: Date;
duration: number;
@@ -302,9 +241,7 @@ type TimelineProps = {
isError: boolean;
};
-type TimelineState = "error" | "pending" | "complete";
-
-function SpanTimeline({ startTime, duration, inProgress, isError }: TimelineProps) {
+export function SpanTimeline({ startTime, duration, inProgress, isError }: TimelineProps) {
const state = isError ? "error" : inProgress ? "pending" : "complete";
return (
<>
@@ -351,20 +288,6 @@ function SpanTimeline({ startTime, duration, inProgress, isError }: TimelineProp
);
}
-function classNameForState(state: TimelineState) {
- switch (state) {
- case "pending": {
- return "bg-pending";
- }
- case "complete": {
- return "bg-success";
- }
- case "error": {
- return "bg-error";
- }
- }
-}
-
function SpanLinkElement({ link }: { link: SpanLink }) {
const organization = useOrganization();
const project = useProject();