Skip to content

Commit 44d443a

Browse files
authored
v3 live run reloading and minor style improvements (#925)
* Initial work creating the Redis publishing and subscribing * Live view is working * Show the live reloading status on the page * Fixed some style issues on the run page with James * Fix for invalid JSX attributes in the ExitIcon svg * Some sexy shit * The end line is now correctly coloured * millisecondsToNanoseconds exported from core/v3 and imported correctly * Fix for e2e tests, we changed the h1 to an h2 * Tidied imports * Removed unused hook
1 parent 2a1273b commit 44d443a

File tree

17 files changed

+453
-247
lines changed

17 files changed

+453
-247
lines changed

apps/webapp/app/assets/icons/ExitIcon.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
export function ExitIcon({ className }: { className?: string }) {
22
return (
33
<svg className={className} viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
4-
<line x1="3.5" y1="8" x2="11.5" y2="8" stroke="currentColor" stroke-linecap="round" />
5-
<line x1="15.5" y1="1.5" x2="15.5" y2="14.5" stroke="currentColor" stroke-linecap="round" />
4+
<line x1="3.5" y1="8" x2="11.5" y2="8" stroke="currentColor" strokeLinecap="round" />
5+
<line x1="15.5" y1="1.5" x2="15.5" y2="14.5" stroke="currentColor" strokeLinecap="round" />
66
<path
77
d="M8.5 4.5L12 8L8.5 11.5"
88
stroke="currentColor"
9-
stroke-linecap="round"
10-
stroke-linejoin="round"
9+
strokeLinecap="round"
10+
strokeLinejoin="round"
1111
/>
1212
</svg>
1313
);

apps/webapp/app/components/VersionLabel.tsx

-31
This file was deleted.

apps/webapp/app/components/primitives/Icon.tsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import React, { FunctionComponent, ReactElement, createElement } from "react";
2-
import { IconNamesOrString, NamedIcon } from "./NamedIcon";
1+
import React, { FunctionComponent, createElement } from "react";
32
import { cn } from "~/utils/cn";
4-
import { render } from "react-dom";
3+
import { IconNamesOrString, NamedIcon } from "./NamedIcon";
54

65
export type RenderIcon =
76
| IconNamesOrString

apps/webapp/app/components/primitives/Timeline.tsx

+1-16
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
useRef,
1010
useState,
1111
} from "react";
12+
import { inverseLerp, lerp } from "~/utils/lerp";
1213

1314
interface MousePosition {
1415
x: number;
@@ -225,19 +226,3 @@ export function FollowCursor({ children }: FollowCursorProps) {
225226
function calculatePixelWidth(minWidth: number, maxWidth: number, scale: number) {
226227
return lerp(minWidth, maxWidth, scale);
227228
}
228-
229-
/** Linearly interpolates between the min/max values, using t.
230-
* It can't go outside the range */
231-
function lerp(min: number, max: number, t: number) {
232-
return min + (max - min) * clamp(t, 0, 1);
233-
}
234-
235-
/** Inverse lerp */
236-
function inverseLerp(min: number, max: number, value: number) {
237-
return (value - min) / (max - min);
238-
}
239-
240-
/** Clamps a value between a min and max */
241-
function clamp(value: number, min: number, max: number) {
242-
return Math.min(max, Math.max(min, value));
243-
}

apps/webapp/app/components/runs/v3/LiveTimer.tsx

+31
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,34 @@ export function LiveTimer({
3939
</Paragraph>
4040
);
4141
}
42+
43+
export function LiveCountUp({
44+
lastUpdated,
45+
updateInterval = 250,
46+
className,
47+
}: {
48+
lastUpdated: Date;
49+
updateInterval?: number;
50+
className?: string;
51+
}) {
52+
const [now, setNow] = useState<Date>();
53+
54+
useEffect(() => {
55+
const interval = setInterval(() => {
56+
const date = new Date();
57+
setNow(date);
58+
}, updateInterval);
59+
60+
return () => clearInterval(interval);
61+
}, [lastUpdated]);
62+
63+
return (
64+
<>
65+
{formatDuration(lastUpdated, now, {
66+
style: "short",
67+
maxDecimalPoints: 0,
68+
units: ["m", "s"],
69+
})}
70+
</>
71+
);
72+
}

apps/webapp/app/components/runs/v3/SpanTitle.tsx

+13-13
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ type SpanTitleProps = {
99
isError: boolean;
1010
style: TaskEventStyle;
1111
level: TaskEventLevel;
12+
isPartial: boolean;
1213
size: "small" | "large";
1314
};
1415

@@ -90,10 +91,6 @@ export function SpanCodePathAccessory({
9091
}
9192

9293
function eventTextClassName(event: Pick<SpanTitleProps, "isError" | "style" | "level">) {
93-
if (event.isError) {
94-
return "text-rose-500";
95-
}
96-
9794
switch (event.level) {
9895
case "TRACE": {
9996
return textClassNameForVariant(event.style.variant);
@@ -107,7 +104,7 @@ function eventTextClassName(event: Pick<SpanTitleProps, "isError" | "style" | "l
107104
return "text-amber-400";
108105
}
109106
case "ERROR": {
110-
return "text-rose-500";
107+
return "text-error";
111108
}
112109
default: {
113110
return textClassNameForVariant(event.style.variant);
@@ -116,29 +113,29 @@ function eventTextClassName(event: Pick<SpanTitleProps, "isError" | "style" | "l
116113
}
117114

118115
export function eventBackgroundClassName(
119-
event: Pick<SpanTitleProps, "isError" | "style" | "level">
116+
event: Pick<SpanTitleProps, "isError" | "style" | "level" | "isPartial">
120117
) {
121118
if (event.isError) {
122-
return "bg-rose-500";
119+
return "bg-error";
123120
}
124121

125122
switch (event.level) {
126123
case "TRACE": {
127-
return backgroundClassNameForVariant(event.style.variant);
124+
return backgroundClassNameForVariant(event.style.variant, event.isPartial);
128125
}
129126
case "LOG":
130127
case "INFO":
131128
case "DEBUG": {
132-
return backgroundClassNameForVariant(event.style.variant);
129+
return backgroundClassNameForVariant(event.style.variant, event.isPartial);
133130
}
134131
case "WARN": {
135132
return "bg-amber-400";
136133
}
137134
case "ERROR": {
138-
return "bg-rose-500";
135+
return "bg-error";
139136
}
140137
default: {
141-
return backgroundClassNameForVariant(event.style.variant);
138+
return backgroundClassNameForVariant(event.style.variant, event.isPartial);
142139
}
143140
}
144141
}
@@ -154,10 +151,13 @@ function textClassNameForVariant(variant: TaskEventStyle["variant"]) {
154151
}
155152
}
156153

157-
function backgroundClassNameForVariant(variant: TaskEventStyle["variant"]) {
154+
function backgroundClassNameForVariant(variant: TaskEventStyle["variant"], isPartial: boolean) {
158155
switch (variant) {
159156
case "primary": {
160-
return "bg-blue-500";
157+
if (isPartial) {
158+
return "bg-blue-500";
159+
}
160+
return "bg-success";
161161
}
162162
default: {
163163
return "bg-charcoal-500";

apps/webapp/app/components/runs/v3/TaskRunStatus.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,15 @@ export function runStatusClassNameColor(status: ExtendedTaskAttemptStatus | null
7474
case "PENDING":
7575
return "text-charcoal-500";
7676
case "EXECUTING":
77-
return "text-blue-500";
77+
return "text-pending";
7878
case "PAUSED":
7979
return "text-amber-300";
8080
case "FAILED":
81-
return "text-rose-500";
81+
return "text-error";
8282
case "CANCELED":
8383
return "text-charcoal-500";
8484
case "COMPLETED":
85-
return "text-green-500";
85+
return "text-success";
8686
default: {
8787
const _exhaustiveCheck: never = status;
8888
throw new Error(`Non-exhaustive match for value: ${status}`);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { useEffect, useLayoutEffect, useState } from "react";
2+
3+
export function useInitialDimensions(ref: React.RefObject<HTMLElement>) {
4+
const [dimensions, setDimensions] = useState<DOMRectReadOnly | null>(null);
5+
6+
useEffect(() => {
7+
if (ref.current) {
8+
setDimensions(ref.current.getBoundingClientRect());
9+
}
10+
}, [ref]);
11+
12+
return dimensions;
13+
}

apps/webapp/app/hooks/useIsOrgChildPage.ts

-11
This file was deleted.

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

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { millisecondsToNanoseconds } from "@trigger.dev/core/v3/utils/durations";
1+
import { millisecondsToNanoseconds } from "@trigger.dev/core/v3";
22
import { createTreeFromFlatItems, flattenTree } from "~/components/primitives/TreeView/TreeView";
33
import { PrismaClient, prisma } from "~/db.server";
44
import { getUsername } from "~/utils/username";
@@ -98,6 +98,15 @@ export class RunPresenter {
9898
}
9999
}
100100

101+
let rootSpanStatus: "executing" | "completed" | "failed" = "executing";
102+
if (events[0]) {
103+
if (events[0].data.isError) {
104+
rootSpanStatus = "failed";
105+
} else if (!events[0].data.isPartial) {
106+
rootSpanStatus = "completed";
107+
}
108+
}
109+
101110
return {
102111
run: {
103112
number: run.number,
@@ -109,6 +118,7 @@ export class RunPresenter {
109118
userName: getUsername(run.runtimeEnvironment.orgMember?.user),
110119
},
111120
},
121+
rootSpanStatus,
112122
events: events,
113123
parentRunFriendlyId:
114124
tree?.id === traceSummary.rootSpan.id ? undefined : traceSummary.rootSpan.runId,

0 commit comments

Comments
 (0)