Skip to content

Commit 187200a

Browse files
ericallamsamejr
andauthored
Feat: Improved run start timeline visibility (#1732)
* Record cold start and execution metrics on attempt executions. Add cold start metrics as span events on attempt spans and display them in the run dashboard * Add deployed tasks run timeline metrics * Add Dequeued event to run timeline and cleanup the run timeline code * Adds variants to storybook * WIP adding new span styles * Added offset progress bar animation * More storybook states * Adds support for the full vertical span to show the same state * Adds error state to timelineLine * Added additional state * Added more line styling * Added progress state to dequeued * Added another state to storybook * Fixed classname error * Updated styles for the span timeline points * Fixes alignment of timeline follow cursor indicator * Adds help text tooltip to timeline span type titles * Fixes type error * Tweaked wording of tooltips * Fixed type error (check this) * Moved isAdmin to a higher level * removed unused admin props * Removed unused Admin filter * Fixed border styling * made the opacity of the timeline states 30% less * Undo type cast * Added a diminished style that’s used for spans (grey progress bar) * Adds new storybook state * Fixed timeline state * Removed state if span isn’t the first * Changed the timestamp span icon --------- Co-authored-by: James Ritchie <james@trigger.dev>
1 parent 26f9a1e commit 187200a

File tree

45 files changed

+2029
-2644
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2029
-2644
lines changed

apps/coordinator/src/index.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -663,9 +663,25 @@ class TaskCoordinator {
663663

664664
await chaosMonkey.call();
665665

666+
const lazyPayload = {
667+
...lazyAttempt.lazyPayload,
668+
metrics: [
669+
...(message.startTime
670+
? [
671+
{
672+
name: "start",
673+
event: "lazy_payload",
674+
timestamp: message.startTime,
675+
duration: Date.now() - message.startTime,
676+
},
677+
]
678+
: []),
679+
],
680+
};
681+
666682
socket.emit("EXECUTE_TASK_RUN_LAZY_ATTEMPT", {
667683
version: "v1",
668-
lazyPayload: lazyAttempt.lazyPayload,
684+
lazyPayload,
669685
});
670686
} catch (error) {
671687
if (error instanceof ChaosMonkey.Error) {

apps/docker-provider/src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,18 @@ class DockerTaskOperations implements TaskOperations {
122122
`--env=POD_NAME=${containerName}`,
123123
`--env=COORDINATOR_HOST=${COORDINATOR_HOST}`,
124124
`--env=COORDINATOR_PORT=${COORDINATOR_PORT}`,
125-
`--env=SCHEDULED_AT_MS=${Date.now()}`,
125+
`--env=TRIGGER_POD_SCHEDULED_AT_MS=${Date.now()}`,
126126
`--name=${containerName}`,
127127
];
128128

129129
if (process.env.ENFORCE_MACHINE_PRESETS) {
130130
runArgs.push(`--cpus=${opts.machine.cpu}`, `--memory=${opts.machine.memory}G`);
131131
}
132132

133+
if (opts.dequeuedAt) {
134+
runArgs.push(`--env=TRIGGER_RUN_DEQUEUED_AT_MS=${opts.dequeuedAt}`);
135+
}
136+
133137
runArgs.push(`${opts.image}`);
134138

135139
try {

apps/kubernetes-provider/src/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,9 @@ class KubernetesTaskOperations implements TaskOperations {
202202
name: "TRIGGER_RUN_ID",
203203
value: opts.runId,
204204
},
205+
...(opts.dequeuedAt
206+
? [{ name: "TRIGGER_RUN_DEQUEUED_AT_MS", value: String(opts.dequeuedAt) }]
207+
: []),
205208
],
206209
volumeMounts: [
207210
{
@@ -518,7 +521,7 @@ class KubernetesTaskOperations implements TaskOperations {
518521
},
519522
},
520523
{
521-
name: "SCHEDULED_AT_MS",
524+
name: "TRIGGER_POD_SCHEDULED_AT_MS",
522525
value: Date.now().toString(),
523526
},
524527
...this.#coordinatorEnvVars,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const variants = {
77
small:
88
"grid place-items-center rounded-full px-[0.4rem] h-4 tracking-wider text-xxs bg-background-dimmed text-text-dimmed uppercase whitespace-nowrap",
99
"extra-small":
10-
"grid place-items-center border border-charcoal-650 rounded-sm px-1 h-4 border-tracking-wider text-xxs bg-background-bright text-blue-500 whitespace-nowrap",
10+
"grid place-items-center border border-charcoal-650 rounded-sm px-1 h-4 tracking-wide text-xxs bg-background-bright text-blue-500 whitespace-nowrap",
1111
outline:
1212
"grid place-items-center rounded-sm px-1.5 h-5 tracking-wider text-xxs border border-dimmed text-text-dimmed uppercase whitespace-nowrap",
1313
"outline-rounded":

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

Lines changed: 131 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ type DateTimeProps = {
77
includeSeconds?: boolean;
88
includeTime?: boolean;
99
showTimezone?: boolean;
10+
previousDate?: Date | string | null; // Add optional previous date for comparison
1011
};
1112

1213
export const DateTime = ({
@@ -70,20 +71,116 @@ export function formatDateTime(
7071
}).format(date);
7172
}
7273

73-
export const DateTimeAccurate = ({ date, timeZone = "UTC" }: DateTimeProps) => {
74+
// New component that only shows date when it changes
75+
export const SmartDateTime = ({ date, previousDate = null, timeZone = "UTC" }: DateTimeProps) => {
7476
const locales = useLocales();
75-
7677
const realDate = typeof date === "string" ? new Date(date) : date;
78+
const realPrevDate = previousDate
79+
? typeof previousDate === "string"
80+
? new Date(previousDate)
81+
: previousDate
82+
: null;
83+
84+
// Initial formatted values
85+
const initialTimeOnly = formatTimeOnly(realDate, timeZone, locales);
86+
const initialWithDate = formatSmartDateTime(realDate, timeZone, locales);
87+
88+
// State for the formatted time
89+
const [formattedDateTime, setFormattedDateTime] = useState<string>(
90+
realPrevDate && isSameDay(realDate, realPrevDate) ? initialTimeOnly : initialWithDate
91+
);
92+
93+
useEffect(() => {
94+
const resolvedOptions = Intl.DateTimeFormat().resolvedOptions();
95+
const userTimeZone = resolvedOptions.timeZone;
96+
97+
// Check if we should show the date
98+
const showDatePart = !realPrevDate || !isSameDay(realDate, realPrevDate);
99+
100+
// Format with appropriate function
101+
setFormattedDateTime(
102+
showDatePart
103+
? formatSmartDateTime(realDate, userTimeZone, locales)
104+
: formatTimeOnly(realDate, userTimeZone, locales)
105+
);
106+
}, [locales, realDate, realPrevDate]);
107+
108+
return <Fragment>{formattedDateTime.replace(/\s/g, String.fromCharCode(32))}</Fragment>;
109+
};
110+
111+
// Helper function to check if two dates are on the same day
112+
function isSameDay(date1: Date, date2: Date): boolean {
113+
return (
114+
date1.getFullYear() === date2.getFullYear() &&
115+
date1.getMonth() === date2.getMonth() &&
116+
date1.getDate() === date2.getDate()
117+
);
118+
}
119+
120+
// Format with date and time
121+
function formatSmartDateTime(date: Date, timeZone: string, locales: string[]): string {
122+
return new Intl.DateTimeFormat(locales, {
123+
month: "short",
124+
day: "numeric",
125+
hour: "numeric",
126+
minute: "numeric",
127+
second: "numeric",
128+
timeZone,
129+
// @ts-ignore fractionalSecondDigits works in most modern browsers
130+
fractionalSecondDigits: 3,
131+
}).format(date);
132+
}
133+
134+
// Format time only
135+
function formatTimeOnly(date: Date, timeZone: string, locales: string[]): string {
136+
return new Intl.DateTimeFormat(locales, {
137+
hour: "numeric",
138+
minute: "numeric",
139+
second: "numeric",
140+
timeZone,
141+
// @ts-ignore fractionalSecondDigits works in most modern browsers
142+
fractionalSecondDigits: 3,
143+
}).format(date);
144+
}
77145

78-
const initialFormattedDateTime = formatDateTimeAccurate(realDate, timeZone, locales);
146+
export const DateTimeAccurate = ({
147+
date,
148+
timeZone = "UTC",
149+
previousDate = null,
150+
}: DateTimeProps) => {
151+
const locales = useLocales();
152+
const realDate = typeof date === "string" ? new Date(date) : date;
153+
const realPrevDate = previousDate
154+
? typeof previousDate === "string"
155+
? new Date(previousDate)
156+
: previousDate
157+
: null;
158+
159+
// Use the new Smart formatting if previousDate is provided
160+
const initialFormattedDateTime = realPrevDate
161+
? isSameDay(realDate, realPrevDate)
162+
? formatTimeOnly(realDate, timeZone, locales)
163+
: formatDateTimeAccurate(realDate, timeZone, locales)
164+
: formatDateTimeAccurate(realDate, timeZone, locales);
79165

80166
const [formattedDateTime, setFormattedDateTime] = useState<string>(initialFormattedDateTime);
81167

82168
useEffect(() => {
83169
const resolvedOptions = Intl.DateTimeFormat().resolvedOptions();
84-
85-
setFormattedDateTime(formatDateTimeAccurate(realDate, resolvedOptions.timeZone, locales));
86-
}, [locales, realDate]);
170+
const userTimeZone = resolvedOptions.timeZone;
171+
172+
if (realPrevDate) {
173+
// Smart formatting based on whether date changed
174+
setFormattedDateTime(
175+
isSameDay(realDate, realPrevDate)
176+
? formatTimeOnly(realDate, userTimeZone, locales)
177+
: formatDateTimeAccurate(realDate, userTimeZone, locales)
178+
);
179+
} else {
180+
// Default behavior when no previous date
181+
setFormattedDateTime(formatDateTimeAccurate(realDate, userTimeZone, locales));
182+
}
183+
}, [locales, realDate, realPrevDate]);
87184

88185
return <Fragment>{formattedDateTime.replace(/\s/g, String.fromCharCode(32))}</Fragment>;
89186
};
@@ -96,7 +193,34 @@ function formatDateTimeAccurate(date: Date, timeZone: string, locales: string[])
96193
minute: "numeric",
97194
second: "numeric",
98195
timeZone,
99-
// @ts-ignore this works in 92.5% of browsers https://caniuse.com/mdn-javascript_builtins_intl_datetimeformat_datetimeformat_options_parameter_options_fractionalseconddigits_parameter
196+
// @ts-ignore fractionalSecondDigits works in most modern browsers
197+
fractionalSecondDigits: 3,
198+
}).format(date);
199+
200+
return formattedDateTime;
201+
}
202+
203+
export const DateTimeShort = ({ date, timeZone = "UTC" }: DateTimeProps) => {
204+
const locales = useLocales();
205+
const realDate = typeof date === "string" ? new Date(date) : date;
206+
const initialFormattedDateTime = formatDateTimeShort(realDate, timeZone, locales);
207+
const [formattedDateTime, setFormattedDateTime] = useState<string>(initialFormattedDateTime);
208+
209+
useEffect(() => {
210+
const resolvedOptions = Intl.DateTimeFormat().resolvedOptions();
211+
setFormattedDateTime(formatDateTimeShort(realDate, resolvedOptions.timeZone, locales));
212+
}, [locales, realDate]);
213+
214+
return <Fragment>{formattedDateTime.replace(/\s/g, String.fromCharCode(32))}</Fragment>;
215+
};
216+
217+
function formatDateTimeShort(date: Date, timeZone: string, locales: string[]): string {
218+
const formattedDateTime = new Intl.DateTimeFormat(locales, {
219+
hour: "numeric",
220+
minute: "numeric",
221+
second: "numeric",
222+
timeZone,
223+
// @ts-ignore fractionalSecondDigits works in most modern browsers
100224
fractionalSecondDigits: 3,
101225
}).format(date);
102226

0 commit comments

Comments
 (0)