chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
import type { SpanEvent } from "@trigger.dev/core/v3";
|
||||
import { millisecondsToNanoseconds } from "@trigger.dev/core/v3/utils/durations";
|
||||
|
||||
export type TimelineEventState = "complete" | "error" | "inprogress" | "delayed";
|
||||
|
||||
export type TimelineLineVariant = "light" | "normal";
|
||||
|
||||
export type TimelineEventVariant =
|
||||
| "start-cap"
|
||||
| "dot-hollow"
|
||||
| "dot-solid"
|
||||
| "start-cap-thick"
|
||||
| "end-cap-thick"
|
||||
| "end-cap";
|
||||
|
||||
export type TimelineSpanEvent = {
|
||||
name: string;
|
||||
offset: number;
|
||||
timestamp: Date;
|
||||
duration?: number;
|
||||
helpText?: string;
|
||||
markerVariant: TimelineEventVariant;
|
||||
lineVariant: TimelineLineVariant;
|
||||
};
|
||||
|
||||
export function createTimelineSpanEventsFromSpanEvents(
|
||||
spanEvents: SpanEvent[],
|
||||
isAdmin: boolean,
|
||||
relativeStartTime?: number
|
||||
): Array<TimelineSpanEvent> {
|
||||
if (!spanEvents) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const matchingSpanEvents = spanEvents.filter((spanEvent) =>
|
||||
spanEvent.name.startsWith("trigger.dev/")
|
||||
);
|
||||
|
||||
if (matchingSpanEvents.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Check if there's a fork event
|
||||
const hasForkEvent = matchingSpanEvents.some(
|
||||
(spanEvent) =>
|
||||
"event" in spanEvent.properties &&
|
||||
typeof spanEvent.properties.event === "string" &&
|
||||
spanEvent.properties.event === "fork"
|
||||
);
|
||||
|
||||
const sortedSpanEvents = [...matchingSpanEvents].sort((a, b) => {
|
||||
if (a.time === b.time) {
|
||||
return a.name.localeCompare(b.name);
|
||||
}
|
||||
|
||||
const aTime = typeof a.time === "string" ? new Date(a.time) : a.time;
|
||||
const bTime = typeof b.time === "string" ? new Date(b.time) : b.time;
|
||||
|
||||
return aTime.getTime() - bTime.getTime();
|
||||
});
|
||||
|
||||
const visibleSpanEvents = sortedSpanEvents.filter((spanEvent) => {
|
||||
const eventName =
|
||||
"event" in spanEvent.properties && typeof spanEvent.properties.event === "string"
|
||||
? spanEvent.properties.event
|
||||
: spanEvent.name;
|
||||
|
||||
// If we're admin, everything is visible
|
||||
if (isAdmin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If there's no fork event, import events are also visible to non-admins
|
||||
if (!hasForkEvent && eventName === "import") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise use normal admin-only logic
|
||||
return !getAdminOnlyForEvent(eventName);
|
||||
});
|
||||
|
||||
if (visibleSpanEvents.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const firstEventTime =
|
||||
typeof visibleSpanEvents[0].time === "string"
|
||||
? new Date(visibleSpanEvents[0].time)
|
||||
: visibleSpanEvents[0].time;
|
||||
|
||||
const $relativeStartTime = relativeStartTime ?? firstEventTime.getTime();
|
||||
|
||||
const events = visibleSpanEvents.map((spanEvent, index) => {
|
||||
const timestamp =
|
||||
typeof spanEvent.time === "string" ? new Date(spanEvent.time) : spanEvent.time;
|
||||
|
||||
const offset = millisecondsToNanoseconds(timestamp.getTime() - $relativeStartTime);
|
||||
|
||||
const duration =
|
||||
"duration" in spanEvent.properties && typeof spanEvent.properties.duration === "number"
|
||||
? spanEvent.properties.duration
|
||||
: undefined;
|
||||
|
||||
const name =
|
||||
"event" in spanEvent.properties && typeof spanEvent.properties.event === "string"
|
||||
? spanEvent.properties.event
|
||||
: spanEvent.name;
|
||||
|
||||
let markerVariant: TimelineEventVariant = "dot-hollow";
|
||||
|
||||
if (index === 0) {
|
||||
markerVariant = "start-cap";
|
||||
}
|
||||
|
||||
return {
|
||||
name: getFriendlyNameForEvent(name, spanEvent.properties),
|
||||
offset,
|
||||
timestamp,
|
||||
duration,
|
||||
helpText: getHelpTextForEvent(name),
|
||||
markerVariant,
|
||||
lineVariant: "light" as const,
|
||||
};
|
||||
});
|
||||
|
||||
// Now sort by offset, ascending
|
||||
events.sort((a, b) => a.offset - b.offset);
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
function getFriendlyNameForEvent(event: string, properties?: Record<string, any>): string {
|
||||
switch (event) {
|
||||
case "dequeue": {
|
||||
return "Dequeued";
|
||||
}
|
||||
case "fork": {
|
||||
return "Launched";
|
||||
}
|
||||
case "create_attempt": {
|
||||
return "Attempt created";
|
||||
}
|
||||
case "import": {
|
||||
return "Importing task file";
|
||||
}
|
||||
case "lazy_payload": {
|
||||
return "Lazy attempt initialized";
|
||||
}
|
||||
case "pod_scheduled": {
|
||||
return "Pod scheduled";
|
||||
}
|
||||
default: {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getAdminOnlyForEvent(event: string): boolean {
|
||||
switch (event) {
|
||||
case "dequeue": {
|
||||
return false;
|
||||
}
|
||||
case "fork": {
|
||||
return false;
|
||||
}
|
||||
case "create_attempt": {
|
||||
return true;
|
||||
}
|
||||
case "import": {
|
||||
return false;
|
||||
}
|
||||
case "lazy_payload": {
|
||||
return true;
|
||||
}
|
||||
case "pod_scheduled": {
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getHelpTextForEvent(event: string): string | undefined {
|
||||
switch (event) {
|
||||
case "dequeue": {
|
||||
return "The run was dequeued from the queue";
|
||||
}
|
||||
case "fork": {
|
||||
return "The process was created to run the task";
|
||||
}
|
||||
case "create_attempt": {
|
||||
return "An attempt was created for the run";
|
||||
}
|
||||
case "import": {
|
||||
return "A task file was imported";
|
||||
}
|
||||
case "lazy_payload": {
|
||||
return "The payload was initialized lazily";
|
||||
}
|
||||
case "pod_scheduled": {
|
||||
return "The Kubernetes pod was scheduled to run";
|
||||
}
|
||||
case "Triggered": {
|
||||
return "The run was triggered";
|
||||
}
|
||||
case "Dequeued": {
|
||||
return "The run was dequeued from the queue";
|
||||
}
|
||||
case "Started": {
|
||||
return "The run began executing";
|
||||
}
|
||||
case "Finished": {
|
||||
return "The run completed execution";
|
||||
}
|
||||
case "Expired": {
|
||||
return "The run expired before it could be started";
|
||||
}
|
||||
default: {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user