chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:32:57 +08:00
commit cd420f9332
4811 changed files with 884702 additions and 0 deletions
@@ -0,0 +1,772 @@
import {
ArrowPathIcon,
ArrowRightIcon,
ClockIcon,
CpuChipIcon,
NoSymbolIcon,
RectangleStackIcon,
} from "@heroicons/react/20/solid";
import { BookOpenIcon, CheckIcon } from "@heroicons/react/24/solid";
import { useLocation } from "@remix-run/react";
import { formatDuration, formatDurationMilliseconds } from "@trigger.dev/core/v3";
import { useCallback, useRef } from "react";
import { TasksIcon } from "~/assets/icons/TasksIcon";
import { MachineLabelCombo } from "~/components/MachineLabelCombo";
import { MachineTooltipInfo } from "~/components/MachineTooltipInfo";
import { Badge } from "~/components/primitives/Badge";
import { Button, LinkButton } from "~/components/primitives/Buttons";
import { Checkbox } from "~/components/primitives/Checkbox";
import { Dialog, DialogTrigger } from "~/components/primitives/Dialog";
import { Header3 } from "~/components/primitives/Headers";
import { PopoverMenuItem } from "~/components/primitives/Popover";
import { useSelectedItems } from "~/components/primitives/SelectedItemsProvider";
import { SimpleTooltip } from "~/components/primitives/Tooltip";
import { TruncatedCopyableValue } from "~/components/primitives/TruncatedCopyableValue";
import { useEnvironment } from "~/hooks/useEnvironment";
import { useRegions } from "~/hooks/useRegions";
import { useFeatures } from "~/hooks/useFeatures";
import { useOrganization } from "~/hooks/useOrganizations";
import { useProject } from "~/hooks/useProject";
import {
type NextRunListAppliedFilters,
type NextRunListItem,
} from "~/presenters/v3/NextRunListPresenter.server";
import { formatCurrencyAccurate } from "~/utils/numberFormatter";
import { docsPath, v3RunSpanPath, v3TestPath, v3TestTaskPath } from "~/utils/pathBuilder";
import { DateTime } from "../../primitives/DateTime";
import { Paragraph } from "../../primitives/Paragraph";
import { Spinner } from "../../primitives/Spinner";
import {
Table,
TableBlankRow,
TableBody,
TableCell,
TableCellMenu,
TableHeader,
TableHeaderCell,
TableRow,
type TableVariant,
} from "../../primitives/Table";
import { CancelRunDialog } from "./CancelRunDialog";
import { RegionLabel } from "./RegionLabel";
import { LiveTimer } from "./LiveTimer";
import { ReplayRunDialog } from "./ReplayRunDialog";
import { RunTag } from "./RunTag";
import {
descriptionForTaskRunStatus,
filterableTaskRunStatuses,
TaskRunStatusCombo,
} from "./TaskRunStatus";
import { RunStatusCellTooltip } from "./RunStatusCellTooltip";
import { TaskTriggerSourceIcon } from "./TaskTriggerSource";
import { useOptimisticLocation } from "~/hooks/useOptimisticLocation";
import { useSearchParams } from "~/hooks/useSearchParam";
import type { TaskTriggerSource } from "@trigger.dev/database";
import { BeakerIcon } from "~/assets/icons/BeakerIcon";
type RunsTableProps = {
total: number;
hasFilters: boolean;
filters: NextRunListAppliedFilters;
showJob?: boolean;
runs: NextRunListItem[];
rootOnlyDefault?: boolean;
isLoading?: boolean;
allowSelection?: boolean;
variant?: TableVariant;
disableAdjacentRows?: boolean;
additionalTableState?: Record<string, string>;
showTopBorder?: boolean;
stickyHeader?: boolean;
childrenStatusesBasePath?: string;
/**
* Display-only write:runs flags from the caller's loader. Default true so
* callers that don't pass them (and OSS, where the ability is permissive)
* keep the controls enabled. The cancel/replay action routes enforce
* write:runs regardless.
*/
canCancelRuns?: boolean;
canReplayRuns?: boolean;
};
export function TaskRunsTable({
total,
hasFilters,
filters,
runs,
rootOnlyDefault,
disableAdjacentRows = false,
isLoading = false,
allowSelection = false,
variant = "dimmed",
additionalTableState,
showTopBorder = true,
stickyHeader = false,
childrenStatusesBasePath,
canCancelRuns = true,
canReplayRuns = true,
}: RunsTableProps) {
const regions = useRegions();
const regionByMasterQueue = new Map(regions.map((r) => [r.masterQueue, r] as const));
const organization = useOrganization();
const project = useProject();
const environment = useEnvironment();
const checkboxes = useRef<(HTMLInputElement | null)[]>([]);
const { has, hasAll, select, deselect, toggle } = useSelectedItems(allowSelection);
const { isManagedCloud } = useFeatures();
const { value } = useSearchParams();
const location = useOptimisticLocation();
const params = new URLSearchParams(location.search || "");
if (!value("rootOnly")) {
params.set("rootOnly", String(rootOnlyDefault));
}
if (additionalTableState) {
for (const [key, val] of Object.entries(additionalTableState)) {
params.set(key, val);
}
}
const search = params.toString();
/** TableState has to be encoded as a separate URI component, so it's merged under one, 'tableState' param */
const tableStateParam = disableAdjacentRows ? "" : encodeURIComponent(search);
const showCompute = isManagedCloud;
const showRegion = environment.type !== "DEVELOPMENT";
const navigateCheckboxes = useCallback(
(event: React.KeyboardEvent<HTMLInputElement>, index: number) => {
//indexes are out by one because of the header row
if (event.key === "ArrowUp" && index > 0) {
checkboxes.current[index - 1]?.focus();
if (event.shiftKey) {
const oldItem = runs.at(index - 1);
const newItem = runs.at(index - 2);
const itemsIds = [oldItem?.friendlyId, newItem?.friendlyId].filter(Boolean);
select(itemsIds);
}
} else if (event.key === "ArrowDown" && index < checkboxes.current.length - 1) {
checkboxes.current[index + 1]?.focus();
if (event.shiftKey) {
const oldItem = runs.at(index - 1);
const newItem = runs.at(index);
const itemsIds = [oldItem?.friendlyId, newItem?.friendlyId].filter(Boolean);
select(itemsIds);
}
}
},
[checkboxes, runs]
);
return (
<Table
variant={variant}
className="max-h-full overflow-y-auto"
showTopBorder={showTopBorder}
stickyHeader={stickyHeader}
>
<TableHeader>
<TableRow>
{allowSelection && (
<TableHeaderCell className="pl-3 pr-0">
{runs.length > 0 && (
<Checkbox
checked={hasAll(runs.map((r) => r.friendlyId))}
onChange={(element) => {
const ids = runs.map((r) => r.friendlyId);
const checked = element.currentTarget.checked;
if (checked) {
select(ids);
} else {
deselect(ids);
}
}}
ref={(r) => {
checkboxes.current[0] = r;
}}
onKeyDown={(event) => navigateCheckboxes(event, 0)}
/>
)}
</TableHeaderCell>
)}
<TableHeaderCell>ID</TableHeaderCell>
<TableHeaderCell>Task</TableHeaderCell>
<TableHeaderCell>Version</TableHeaderCell>
<TableHeaderCell
disableTooltipHoverableContent
tooltip={
<div className="flex flex-col divide-y divide-grid-dimmed">
{filterableTaskRunStatuses.map((status) => (
<div
key={status}
className="grid grid-cols-[8rem_1fr] gap-x-2 py-2 first:pt-1 last:pb-1"
>
<div className="mb-0.5 flex items-center gap-1.5 whitespace-nowrap">
<TaskRunStatusCombo status={status} />
</div>
<Paragraph variant="extra-small" className="text-wrap! text-text-dimmed">
{descriptionForTaskRunStatus(status)}
</Paragraph>
</div>
))}
</div>
}
>
Status
</TableHeaderCell>
<TableHeaderCell>Started</TableHeaderCell>
<TableHeaderCell
colSpan={3}
disableTooltipHoverableContent
tooltip={
<div className="flex max-w-xs flex-col gap-4 p-1">
<div>
<div className="mb-0.5 flex items-center gap-1.5">
<RectangleStackIcon className="size-4 text-text-dimmed" />
<Header3>Queued duration</Header3>
</div>
<Paragraph variant="small" className="text-wrap! text-text-dimmed">
The amount of time from when the run was created to it starting to run.
</Paragraph>
</div>
<div>
<div className="mb-0.5 flex items-center gap-1.5">
<ClockIcon className="size-4 text-blue-500" /> <Header3>Run duration</Header3>
</div>
<Paragraph variant="small" className="text-wrap! text-text-dimmed">
The total amount of time from the run starting to it finishing. This includes
all time spent waiting.
</Paragraph>
</div>
<div>
<div className="mb-0.5 flex items-center gap-1.5">
<CpuChipIcon className="size-4 text-success" />
<Header3>Compute duration</Header3>
</div>
<Paragraph variant="small" className="text-wrap! text-text-dimmed">
The amount of compute time used in the run. This does not include time spent
waiting.
</Paragraph>
</div>
</div>
}
>
Duration
</TableHeaderCell>
{showCompute && (
<>
<TableHeaderCell>Compute</TableHeaderCell>
</>
)}
<TableHeaderCell className="pl-4" tooltip={<MachineTooltipInfo />}>
Machine
</TableHeaderCell>
<TableHeaderCell>Queue</TableHeaderCell>
{showRegion && <TableHeaderCell>Region</TableHeaderCell>}
<TableHeaderCell>Test</TableHeaderCell>
<TableHeaderCell>Created at</TableHeaderCell>
<TableHeaderCell
tooltip={
<div className="max-w-xs p-1">
<Paragraph variant="small" className="text-wrap! text-text-dimmed" spacing>
When you want to trigger a task now, but have it run at a later time, you can use
the delay option.
</Paragraph>
<Paragraph variant="small" className="text-wrap! text-text-dimmed" spacing>
Runs that are delayed and have not been enqueued yet will display in the dashboard
with a Delayed status.
</Paragraph>
<LinkButton
to={docsPath("v3/triggering")}
variant="docs/small"
LeadingIcon={BookOpenIcon}
className="mt-3"
>
Read docs
</LinkButton>
</div>
}
>
Delayed until
</TableHeaderCell>
<TableHeaderCell
tooltip={
<div className="max-w-xs p-1">
<Paragraph variant="small" className="text-wrap! text-text-dimmed" spacing>
You can set a TTL (time to live) when triggering a task, which will automatically
expire the run if it hasnt started within the specified time.
</Paragraph>
<Paragraph variant="small" className="text-wrap! text-text-dimmed" spacing>
All runs in development have a default ttl of 10 minutes. You can disable this by
setting the ttl option.
</Paragraph>
<LinkButton
to={docsPath("v3/triggering")}
variant="docs/small"
LeadingIcon={BookOpenIcon}
className="mt-3"
>
Read docs
</LinkButton>
</div>
}
>
TTL
</TableHeaderCell>
<TableHeaderCell
tooltip={
<div className="max-w-xs p-1">
<Paragraph variant="small" className="text-wrap! text-text-dimmed" spacing>
You can add tags to a run and then filter runs using them.
</Paragraph>
<Paragraph variant="small" className="text-wrap! text-text-dimmed" spacing>
You can add tags when triggering a run or inside the run function.
</Paragraph>
<LinkButton
to={docsPath("v3/tags")}
variant="docs/small"
LeadingIcon={BookOpenIcon}
className="mt-3"
>
Read docs
</LinkButton>
</div>
}
>
Tags
</TableHeaderCell>
<TableHeaderCell>
<span className="sr-only">Go to page</span>
</TableHeaderCell>
</TableRow>
</TableHeader>
<TableBody>
{total === 0 && !hasFilters ? (
<TableBlankRow colSpan={showRegion ? 16 : 15}>
{!isLoading && <NoRuns title="No runs found" />}
</TableBlankRow>
) : runs.length === 0 ? (
<BlankState isLoading={isLoading} filters={filters} showRegion={showRegion} />
) : (
runs.map((run, index) => {
const searchParams = new URLSearchParams();
if (tableStateParam) {
searchParams.set("tableState", tableStateParam);
}
const path = v3RunSpanPath(
organization,
project,
run.environment,
run,
{
spanId: run.spanId,
},
searchParams
);
return (
<TableRow key={run.id}>
{allowSelection && (
<TableCell className="pl-3 pr-0">
<Checkbox
checked={has(run.friendlyId)}
onChange={() => {
toggle(run.friendlyId);
}}
ref={(r) => {
checkboxes.current[index + 1] = r;
}}
onKeyDown={(event) => navigateCheckboxes(event, index + 1)}
/>
</TableCell>
)}
<TableCell to={path} isTabbableCell>
<TruncatedCopyableValue value={run.friendlyId} />
</TableCell>
<TableCell to={path}>
<span className="flex items-center gap-x-1">
<TaskTriggerSourceIcon
source={run.taskKind as TaskTriggerSource}
className="size-3.5 flex-none"
/>
{run.taskIdentifier}
{run.rootTaskRunId === null ? <Badge variant="extra-small">Root</Badge> : null}
</span>
</TableCell>
<TableCell to={path}>{run.version ?? ""}</TableCell>
<TableCell to={path}>
{run.rootTaskRunId === null && childrenStatusesBasePath ? (
<RunStatusCellTooltip
friendlyId={run.friendlyId}
status={run.status}
hasFinished={run.hasFinished}
childrenStatusesBasePath={childrenStatusesBasePath}
/>
) : (
<SimpleTooltip
content={descriptionForTaskRunStatus(run.status)}
disableHoverableContent
button={<TaskRunStatusCombo status={run.status} />}
/>
)}
</TableCell>
<TableCell to={path}>
{run.startedAt ? <DateTime date={run.startedAt} /> : ""}
</TableCell>
<TableCell to={path} className="w-[1%]" actionClassName="pr-0 tabular-nums">
<div className="flex items-center gap-1">
<RectangleStackIcon className="size-4 text-text-dimmed" />
{run.isPending ? (
""
) : run.startedAt ? (
formatDuration(new Date(run.createdAt), new Date(run.startedAt), {
style: "short",
})
) : run.isCancellable ? (
<LiveTimer startTime={new Date(run.createdAt)} />
) : (
formatDuration(new Date(run.createdAt), new Date(run.updatedAt), {
style: "short",
})
)}
</div>
</TableCell>
<TableCell to={path} className="w-[1%]" actionClassName="px-4 tabular-nums">
<div className="flex items-center gap-1">
<ClockIcon className="size-4 text-blue-500" />
{run.startedAt && run.finishedAt ? (
formatDuration(new Date(run.startedAt), new Date(run.finishedAt), {
style: "short",
})
) : run.startedAt ? (
<LiveTimer startTime={new Date(run.startedAt)} />
) : (
""
)}
</div>
</TableCell>
<TableCell to={path} actionClassName="pl-0 tabular-nums">
<div className="flex items-center gap-1">
<CpuChipIcon className="size-4 text-success" />
{run.usageDurationMs > 0
? formatDurationMilliseconds(run.usageDurationMs, {
style: "short",
})
: ""}
</div>
</TableCell>
{showCompute && (
<TableCell to={path} className="tabular-nums">
{run.costInCents > 0
? formatCurrencyAccurate((run.costInCents + run.baseCostInCents) / 100)
: ""}
</TableCell>
)}
<TableCell to={path}>
<MachineLabelCombo preset={run.machinePreset} />
</TableCell>
<TableCell to={path}>
{run.queue.type === "task" ? (
<SimpleTooltip
buttonClassName="w-fit"
button={
<span className="flex items-center gap-1">
<TasksIcon className="size-[1.125rem] text-blue-500" />
<span>{run.queue.name}</span>
</span>
}
content={`This queue was automatically created from your "${run.queue.name}" task`}
disableHoverableContent
/>
) : (
<SimpleTooltip
buttonClassName="w-fit"
button={
<span className="flex items-center gap-1">
<RectangleStackIcon className="size-[1.125rem] text-purple-500" />
<span>{run.queue.name}</span>
</span>
}
content={`This is a custom queue you added in your code.`}
disableHoverableContent
/>
)}
</TableCell>
{showRegion && (
<TableCell to={path}>
{run.region ? (
<RegionLabel
region={regionByMasterQueue.get(run.region) ?? { name: run.region }}
iconClassName="size-4"
/>
) : (
""
)}
</TableCell>
)}
<TableCell to={path}>
{run.isTest ? (
<CheckIcon className="size-4 text-text-dimmed group-hover/table-row:text-text-bright" />
) : (
""
)}
</TableCell>
<TableCell to={path}>
{run.createdAt ? <DateTime date={run.createdAt} /> : ""}
</TableCell>
<TableCell to={path}>
{run.delayUntil ? <DateTime date={run.delayUntil} /> : ""}
</TableCell>
<TableCell to={path}>{run.ttl ?? ""}</TableCell>
<TableCell to={path} actionClassName="py-1" className="pr-16">
<div className="flex gap-1">
{run.tags.map((tag) => <RunTag key={tag} tag={tag} />) || ""}
</div>
</TableCell>
<RunActionsCell
run={run}
path={path}
canCancelRuns={canCancelRuns}
canReplayRuns={canReplayRuns}
/>
</TableRow>
);
})
)}
{isLoading && (
<TableBlankRow
colSpan={showRegion ? 16 : 15}
className="absolute left-0 top-0 flex h-full w-full items-center justify-center gap-2 bg-background-dimmed"
>
<Spinner /> <span className="text-text-dimmed">Loading</span>
</TableBlankRow>
)}
</TableBody>
</Table>
);
}
function RunActionsCell({
run,
path,
canCancelRuns,
canReplayRuns,
}: {
run: NextRunListItem;
path: string;
canCancelRuns: boolean;
canReplayRuns: boolean;
}) {
const location = useLocation();
if (!run.isCancellable && !run.isReplayable) return <TableCell to={path}>{""}</TableCell>;
return (
<TableCellMenu
isSticky
popoverContent={
<>
<PopoverMenuItem
to={path}
icon={ArrowRightIcon}
leadingIconClassName="text-blue-500"
title="View run"
/>
{run.isCancellable &&
(canCancelRuns ? (
<Dialog>
<DialogTrigger
asChild
className="size-6 rounded-sm p-1 text-text-dimmed transition hover:bg-background-raised hover:text-text-bright"
>
<Button
variant="small-menu-item"
LeadingIcon={NoSymbolIcon}
leadingIconClassName="text-error"
fullWidth
textAlignLeft
className="w-full px-1.5 py-[0.9rem]"
>
Cancel run
</Button>
</DialogTrigger>
<CancelRunDialog
runFriendlyId={run.friendlyId}
redirectPath={`${location.pathname}${location.search}`}
/>
</Dialog>
) : (
<Button
variant="small-menu-item"
LeadingIcon={NoSymbolIcon}
leadingIconClassName="text-error"
fullWidth
textAlignLeft
className="w-full px-1.5 py-[0.9rem]"
disabled
tooltip="You don't have permission to cancel runs"
>
Cancel run
</Button>
))}
{run.isReplayable &&
(canReplayRuns ? (
<Dialog>
<DialogTrigger
asChild
className="h-6 w-6 rounded-sm p-1 text-text-dimmed transition hover:bg-background-raised hover:text-text-bright"
>
<Button
variant="small-menu-item"
LeadingIcon={ArrowPathIcon}
leadingIconClassName="text-success"
fullWidth
textAlignLeft
className="w-full px-1.5 py-[0.9rem]"
>
Replay run
</Button>
</DialogTrigger>
<ReplayRunDialog
runFriendlyId={run.friendlyId}
failedRedirect={`${location.pathname}${location.search}`}
/>
</Dialog>
) : (
<Button
variant="small-menu-item"
LeadingIcon={ArrowPathIcon}
leadingIconClassName="text-success"
fullWidth
textAlignLeft
className="w-full px-1.5 py-[0.9rem]"
disabled
tooltip="You don't have permission to replay runs"
>
Replay run
</Button>
))}
</>
}
hiddenButtons={
<>
{run.isCancellable && canCancelRuns && (
<SimpleTooltip
button={
<Dialog>
<DialogTrigger
asChild
className="size-6 rounded-sm p-1 text-text-bright transition hover:bg-background-raised"
>
<NoSymbolIcon className="size-3" />
</DialogTrigger>
<CancelRunDialog
runFriendlyId={run.friendlyId}
redirectPath={`${location.pathname}${location.search}`}
/>
</Dialog>
}
content="Cancel run"
side="left"
disableHoverableContent
/>
)}
{run.isCancellable && canCancelRuns && run.isReplayable && canReplayRuns && (
<div className="mx-0.5 h-6 w-px bg-grid-dimmed" />
)}
{run.isReplayable && canReplayRuns && (
<SimpleTooltip
button={
<Dialog>
<DialogTrigger
asChild
className="h-6 w-6 rounded-sm p-1 text-text-bright transition hover:bg-background-raised"
>
<ArrowPathIcon className="size-3" />
</DialogTrigger>
<ReplayRunDialog
runFriendlyId={run.friendlyId}
failedRedirect={`${location.pathname}${location.search}`}
/>
</Dialog>
}
content="Replay run…"
side="left"
disableHoverableContent
/>
)}
</>
}
/>
);
}
function NoRuns({ title }: { title: string }) {
return (
<div className="flex items-center justify-center">
<Paragraph className="w-auto">{title}</Paragraph>
</div>
);
}
function BlankState({
isLoading,
filters,
showRegion,
}: Pick<RunsTableProps, "isLoading" | "filters"> & { showRegion: boolean }) {
const organization = useOrganization();
const project = useProject();
const environment = useEnvironment();
const colSpan = showRegion ? 16 : 15;
if (isLoading) return <TableBlankRow colSpan={colSpan}></TableBlankRow>;
const { tasks, from, to, ...otherFilters } = filters;
const singleTaskFromFilters = filters.tasks.length === 1 ? filters.tasks[0] : null;
const testPath = singleTaskFromFilters
? v3TestTaskPath(organization, project, environment, { taskIdentifier: singleTaskFromFilters })
: v3TestPath(organization, project, environment);
if (
filters.tasks.length === 1 &&
filters.from === undefined &&
filters.to === undefined &&
Object.values(otherFilters).every((filterArray) => filterArray.length === 0)
) {
return (
<TableBlankRow colSpan={colSpan}>
<Paragraph className="w-auto" variant="base/bright" spacing>
There are no runs for {filters.tasks[0]}
</Paragraph>
</TableBlankRow>
);
}
return (
<TableBlankRow colSpan={colSpan}>
<div className="flex flex-col items-center justify-center gap-6">
<Paragraph className="w-auto" variant="base/bright">
No runs match your filters. Try refreshing, modifying your filters or run a test.
</Paragraph>
<div className="flex items-center gap-2">
<Button
LeadingIcon={ArrowPathIcon}
variant="secondary/medium"
onClick={() => {
window.location.reload();
}}
>
Refresh
</Button>
<Paragraph>or</Paragraph>
<LinkButton
LeadingIcon={BeakerIcon}
leadingIconClassName="text-tests"
variant="secondary/medium"
to={testPath}
>
Run a test
</LinkButton>
</div>
</div>
</TableBlankRow>
);
}