import { ArrowRightIcon } from "@heroicons/react/20/solid"; import { CheckIcon } from "@heroicons/react/24/solid"; import { useLocation, useNavigation } from "@remix-run/react"; import { formatDuration } from "@trigger.dev/core/v3/utils/durations"; import { RunsIconExtraSmall } from "~/assets/icons/RunsIcon"; import { MiddleTruncate } from "~/components/primitives/MiddleTruncate"; import { DateTime } from "~/components/primitives/DateTime"; import { Paragraph } from "~/components/primitives/Paragraph"; import { PopoverMenuItem } from "~/components/primitives/Popover"; import { Spinner } from "~/components/primitives/Spinner"; import { Table, TableBlankRow, TableBody, TableCell, TableCellMenu, TableHeader, TableHeaderCell, TableRow, } from "~/components/primitives/Table"; import { SimpleTooltip } from "~/components/primitives/Tooltip"; import { LiveTimer } from "~/components/runs/v3/LiveTimer"; import { RunTag } from "~/components/runs/v3/RunTag"; import { useEnvironment } from "~/hooks/useEnvironment"; import { useOrganization } from "~/hooks/useOrganizations"; import { useProject } from "~/hooks/useProject"; import { type SessionListItem, type SessionList, } from "~/presenters/v3/SessionListPresenter.server"; import { v3RunPath, v3RunsPath, v3SessionPath } from "~/utils/pathBuilder"; import { descriptionForSessionStatus, SessionStatusCombo, allSessionStatuses, } from "./SessionStatus"; type SessionsTableProps = Pick & { showTopBorder?: boolean; stickyHeader?: boolean; }; export function SessionsTable({ sessions, hasFilters, showTopBorder = true, stickyHeader = false, }: SessionsTableProps) { const navigation = useNavigation(); const location = useLocation(); const isLoading = navigation.state !== "idle" && navigation.location?.pathname === location.pathname; const organization = useOrganization(); const project = useProject(); const environment = useEnvironment(); return ( ID {allSessionStatuses.map((status) => (
{descriptionForSessionStatus(status)}
))} } disableTooltipHoverableContent > Status
Type Agent ID Test Tags Created Duration Actions
{sessions.length === 0 ? (
{hasFilters ? "No sessions match these filters" : "No sessions in this environment yet"}
) : ( sessions.map((session) => { const runPath = session.currentRunFriendlyId ? v3RunPath(organization, project, environment, { friendlyId: session.currentRunFriendlyId, }) : undefined; const displayId = session.externalId ?? session.friendlyId; const sessionPath = v3SessionPath(organization, project, environment, { friendlyId: session.friendlyId, }); const allRunsPath = v3RunsPath(organization, project, environment, { tags: [`chat:${displayId}`], }); return (
} /> {session.type}
{session.isTest ? "Yes" : "No"} {session.isTest ? ( ) : ( )} {session.tags.length > 0 ? (
{session.tags.map((tag) => ( ))}
) : ( )}
); }) )} {isLoading && ( Loading… )}
); } function SessionDuration({ session }: { session: SessionListItem }) { // Active sessions tick live; closed/expired sessions freeze at the // moment they ended (closedAt for explicit closes, expiresAt when the // TTL ran out without a close call). const endedAt = session.status === "CLOSED" ? session.closedAt : session.status === "EXPIRED" ? session.expiresAt : undefined; if (endedAt) { return ( <>{formatDuration(new Date(session.createdAt), new Date(endedAt), { style: "short" })} ); } return ; } function SessionActionsCell({ runPath, allRunsPath }: { runPath?: string; allRunsPath: string }) { return ( {runPath && ( )} } /> ); }