diff --git a/apps/webapp/app/assets/icons/MachineIcon.tsx b/apps/webapp/app/assets/icons/MachineIcon.tsx
new file mode 100644
index 0000000000..a58023a283
--- /dev/null
+++ b/apps/webapp/app/assets/icons/MachineIcon.tsx
@@ -0,0 +1,221 @@
+import { cn } from "~/utils/cn";
+
+export function MachineIcon({ preset, className }: { preset?: string; className?: string }) {
+ if (!preset) {
+ return ;
+ }
+
+ switch (preset) {
+ case "no-machine":
+ return ;
+ case "micro":
+ return ;
+ case "small-1x":
+ return ;
+ case "small-2x":
+ return ;
+ case "medium-1x":
+ return ;
+ case "medium-2x":
+ return ;
+ case "large-1x":
+ return ;
+ case "large-2x":
+ return ;
+ default:
+ return ;
+ }
+}
+
+function MachineDefaultIcon({ className }: { className?: string }) {
+ return (
+
+ );
+}
+
+function MachineIconNoMachine({ className }: { className?: string }) {
+ return (
+
+ );
+}
+
+function MachineIconMicro({ className }: { className?: string }) {
+ return (
+
+ );
+}
+
+function MachineIconSmall1x({ className }: { className?: string }) {
+ return (
+
+ );
+}
+
+function MachineIconSmall2x({ className }: { className?: string }) {
+ return (
+
+ );
+}
+
+function MachineIconMedium1x({ className }: { className?: string }) {
+ return (
+
+ );
+}
+
+function MachineIconMedium2x({ className }: { className?: string }) {
+ return (
+
+ );
+}
+
+function MachineIconLarge1x({ className }: { className?: string }) {
+ return (
+
+ );
+}
+
+function MachineIconLarge2x({ className }: { className?: string }) {
+ return (
+
+ );
+}
diff --git a/apps/webapp/app/components/MachineLabelCombo.tsx b/apps/webapp/app/components/MachineLabelCombo.tsx
new file mode 100644
index 0000000000..40a37e59a6
--- /dev/null
+++ b/apps/webapp/app/components/MachineLabelCombo.tsx
@@ -0,0 +1,59 @@
+import { type MachinePresetName } from "@trigger.dev/core/v3";
+import { MachineIcon } from "~/assets/icons/MachineIcon";
+import { cn } from "~/utils/cn";
+
+export function MachineLabelCombo({
+ preset,
+ className,
+ iconClassName,
+ labelClassName,
+}: {
+ preset?: MachinePresetName | null;
+ className?: string;
+ iconClassName?: string;
+ labelClassName?: string;
+}) {
+ return (
+
+
+
+
+ );
+}
+
+export function MachineLabel({
+ preset,
+ className,
+}: {
+ preset?: MachinePresetName | null;
+ className?: string;
+}) {
+ return (
+ {formatMachinePresetName(preset)}
+ );
+}
+
+export function formatMachinePresetName(preset?: MachinePresetName | null): string {
+ if (!preset) {
+ return "No machine yet";
+ }
+
+ switch (preset) {
+ case "micro":
+ return "Micro";
+ case "small-1x":
+ return "Small 1x";
+ case "small-2x":
+ return "Small 2x";
+ case "medium-1x":
+ return "Medium 1x";
+ case "medium-2x":
+ return "Medium 2x";
+ case "large-1x":
+ return "Large 1x";
+ case "large-2x":
+ return "Large 2x";
+ default:
+ return preset;
+ }
+}
diff --git a/apps/webapp/app/components/MachineTooltipInfo.tsx b/apps/webapp/app/components/MachineTooltipInfo.tsx
new file mode 100644
index 0000000000..3b3616288b
--- /dev/null
+++ b/apps/webapp/app/components/MachineTooltipInfo.tsx
@@ -0,0 +1,63 @@
+import { MachineIcon } from "~/assets/icons/MachineIcon";
+import { docsPath } from "~/utils/pathBuilder";
+import { LinkButton } from "./primitives/Buttons";
+import { Header3 } from "./primitives/Headers";
+import { Paragraph } from "./primitives/Paragraph";
+import { BookOpenIcon } from "@heroicons/react/20/solid";
+
+export function MachineTooltipInfo() {
+ return (
+
+
+
+
+ No machine yet
+
+
+ The machine is set at the moment the run is dequeued.
+
+
+
+
+
+ Micro
+
+
+ The smallest and cheapest machine available.
+
+
+
+
+ Small 1x & 2x
+
+
+ Smaller machines for basic workloads. Small 1x is the default machine.
+
+
+
+
+ Medium 1x & 2x
+
+
+ Medium machines for more demanding workloads.
+
+
+
+
+ Large 1x & 2x
+
+
+ Larger machines for the most demanding workloads such as video processing. The larger the
+ machine, the more expensive it is.
+
+
+
+ Read docs
+
+
+ );
+}
diff --git a/apps/webapp/app/components/runs/v3/TaskRunsTable.tsx b/apps/webapp/app/components/runs/v3/TaskRunsTable.tsx
index f555f26cb4..4a76cd18dd 100644
--- a/apps/webapp/app/components/runs/v3/TaskRunsTable.tsx
+++ b/apps/webapp/app/components/runs/v3/TaskRunsTable.tsx
@@ -8,7 +8,11 @@ import {
} from "@heroicons/react/20/solid";
import { BeakerIcon, BookOpenIcon, CheckIcon } from "@heroicons/react/24/solid";
import { useLocation } from "@remix-run/react";
-import { formatDuration, formatDurationMilliseconds } from "@trigger.dev/core/v3";
+import {
+ formatDuration,
+ formatDurationMilliseconds,
+ MachinePresetName,
+} from "@trigger.dev/core/v3";
import { useCallback, useRef } from "react";
import { Badge } from "~/components/primitives/Badge";
import { Button, LinkButton } from "~/components/primitives/Buttons";
@@ -52,6 +56,9 @@ import {
filterableTaskRunStatuses,
TaskRunStatusCombo,
} from "./TaskRunStatus";
+import { MachineIcon } from "~/assets/icons/MachineIcon";
+import { MachineLabelCombo } from "~/components/MachineLabelCombo";
+import { MachineTooltipInfo } from "~/components/MachineTooltipInfo";
type RunsTableProps = {
total: number;
@@ -201,6 +208,9 @@ export function TaskRunsTable({
Compute
>
)}
+ }>
+ Machine
+
Test
Created at
)}
+
+
+
{run.isTest ? : "–"}
diff --git a/apps/webapp/app/presenters/v3/NextRunListPresenter.server.ts b/apps/webapp/app/presenters/v3/NextRunListPresenter.server.ts
index bc061b36d7..9217c5039d 100644
--- a/apps/webapp/app/presenters/v3/NextRunListPresenter.server.ts
+++ b/apps/webapp/app/presenters/v3/NextRunListPresenter.server.ts
@@ -9,6 +9,7 @@ import { timeFilters } from "~/components/runs/v3/SharedFilters";
import { findDisplayableEnvironment } from "~/models/runtimeEnvironment.server";
import { getAllTaskIdentifiers } from "~/models/task.server";
import { RunsRepository } from "~/services/runsRepository.server";
+import { machinePresetFromRun } from "~/v3/machinePresets.server";
import { ServiceValidationError } from "~/v3/services/baseService.server";
import { isCancellableRunStatus, isFinalRunStatus, isPendingRunStatus } from "~/v3/taskStatus";
@@ -231,6 +232,7 @@ export class NextRunListPresenter {
rootTaskRunId: run.rootTaskRunId,
metadata: run.metadata,
metadataType: run.metadataType,
+ machinePreset: run.machinePreset ? machinePresetFromRun(run)?.name : undefined,
};
}),
pagination: {
diff --git a/apps/webapp/app/presenters/v3/SpanPresenter.server.ts b/apps/webapp/app/presenters/v3/SpanPresenter.server.ts
index 0c16a5cc99..7d3c219bee 100644
--- a/apps/webapp/app/presenters/v3/SpanPresenter.server.ts
+++ b/apps/webapp/app/presenters/v3/SpanPresenter.server.ts
@@ -8,7 +8,7 @@ import { getMaxDuration } from "@trigger.dev/core/v3/isomorphic";
import { RUNNING_STATUSES } from "~/components/runs/v3/TaskRunStatus";
import { logger } from "~/services/logger.server";
import { eventRepository, rehydrateAttribute } from "~/v3/eventRepository.server";
-import { machinePresetFromName } from "~/v3/machinePresets.server";
+import { machinePresetFromName, machinePresetFromRun } from "~/v3/machinePresets.server";
import { getTaskEventStoreTableForRun, type TaskEventStoreTable } from "~/v3/taskEventStore.server";
import { isFailedRunStatus, isFinalRunStatus } from "~/v3/taskStatus";
import { BasePresenter } from "./basePresenter.server";
@@ -269,6 +269,8 @@ export class SpanPresenter extends BasePresenter {
})
: undefined;
+ const machine = run.machinePreset ? machinePresetFromRun(run) : undefined;
+
const context = {
task: {
id: run.taskIdentifier,
@@ -307,9 +309,7 @@ export class SpanPresenter extends BasePresenter {
slug: run.project.slug,
name: run.project.name,
},
- machine: run.machinePreset
- ? machinePresetFromName(run.machinePreset as MachinePresetName)
- : undefined,
+ machine,
};
return {
@@ -372,6 +372,7 @@ export class SpanPresenter extends BasePresenter {
workerQueue: run.workerQueue,
spanId: run.spanId,
isCached: !!span.originalRun,
+ machinePreset: machine?.name,
};
}
diff --git a/apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx b/apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
index 2c85b0aa56..7158c57b01 100644
--- a/apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
+++ b/apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
@@ -7,6 +7,7 @@ import {
import { type LoaderFunctionArgs } from "@remix-run/server-runtime";
import {
formatDurationMilliseconds,
+ MachinePresetName,
type TaskRunError,
taskRunErrorEnhancer,
} from "@trigger.dev/core/v3";
@@ -18,6 +19,8 @@ import { AdminDebugRun } from "~/components/admin/debugRun";
import { CodeBlock } from "~/components/code/CodeBlock";
import { EnvironmentCombo } from "~/components/environments/EnvironmentLabel";
import { Feedback } from "~/components/Feedback";
+import { MachineLabelCombo } from "~/components/MachineLabelCombo";
+import { MachineTooltipInfo } from "~/components/MachineTooltipInfo";
import { Button, LinkButton } from "~/components/primitives/Buttons";
import { Callout } from "~/components/primitives/Callout";
import { DateTime, DateTimeAccurate } from "~/components/primitives/DateTime";
@@ -36,7 +39,6 @@ import {
import { TabButton, TabContainer } from "~/components/primitives/Tabs";
import { TextLink } from "~/components/primitives/TextLink";
import { InfoIconTooltip, SimpleTooltip } from "~/components/primitives/Tooltip";
-import { RuntimeIcon } from "~/components/RuntimeIcon";
import { RunTimeline, RunTimelineEvent, SpanTimeline } from "~/components/run/RunTimeline";
import { PacketDisplay } from "~/components/runs/v3/PacketDisplay";
import { RunIcon } from "~/components/runs/v3/RunIcon";
@@ -46,6 +48,7 @@ import { SpanTitle } from "~/components/runs/v3/SpanTitle";
import { TaskRunAttemptStatusCombo } from "~/components/runs/v3/TaskRunAttemptStatus";
import { TaskRunStatusCombo, TaskRunStatusReason } from "~/components/runs/v3/TaskRunStatus";
import { WaitpointDetailTable } from "~/components/runs/v3/WaitpointDetails";
+import { RuntimeIcon } from "~/components/RuntimeIcon";
import { WarmStartCombo } from "~/components/WarmStarts";
import { useEnvironment } from "~/hooks/useEnvironment";
import { useOrganization } from "~/hooks/useOrganizations";
@@ -615,6 +618,7 @@ function RunBody({
)}
+
{run.schedule && (
Schedule
@@ -681,6 +685,17 @@ function RunBody({
: "–"}
+
+
+
+ Machine
+ } />
+
+
+
+
+
+
Run invocation cost
@@ -724,12 +739,15 @@ function RunBody({
{run.engine}
{isAdmin && (
- <>
+
+
+ Admin only
+
Worker queue
{run.workerQueue}
- >
+
)}
diff --git a/apps/webapp/app/routes/resources.runs.$runParam.ts b/apps/webapp/app/routes/resources.runs.$runParam.ts
index 7866ee9327..899dbb63f0 100644
--- a/apps/webapp/app/routes/resources.runs.$runParam.ts
+++ b/apps/webapp/app/routes/resources.runs.$runParam.ts
@@ -5,7 +5,7 @@ import { RUNNING_STATUSES } from "~/components/runs/v3/TaskRunStatus";
import { $replica } from "~/db.server";
import { requireUserId } from "~/services/session.server";
import { v3RunParamsSchema } from "~/utils/pathBuilder";
-import { machinePresetFromName } from "~/v3/machinePresets.server";
+import { machinePresetFromName, machinePresetFromRun } from "~/v3/machinePresets.server";
import { FINAL_ATTEMPT_STATUSES, isFinalRunStatus } from "~/v3/taskStatus";
export type RunInspectorData = UseDataFunctionReturn;
@@ -183,9 +183,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
slug: run.project.slug,
name: run.project.name,
},
- machine: run.machinePreset
- ? machinePresetFromName(run.machinePreset as MachinePresetName)
- : undefined,
+ machine: run.machinePreset ? machinePresetFromRun(run) : undefined,
};
return typedjson({
diff --git a/apps/webapp/app/services/runsRepository.server.ts b/apps/webapp/app/services/runsRepository.server.ts
index 156efa45e3..acc3670206 100644
--- a/apps/webapp/app/services/runsRepository.server.ts
+++ b/apps/webapp/app/services/runsRepository.server.ts
@@ -169,6 +169,7 @@ export class RunsRepository {
batchId: true,
metadata: true,
metadataType: true,
+ machinePreset: true,
},
});