Skip to content

Commit f72b6d2

Browse files
Ekaterina BulatovaEkaterina Bulatova
authored andcommitted
feat(webapp): add helpers for runs list live reload
Extract mapRunToLiveFields for patching list rows from poll responses. Add loadProjectEnvironmentFromRequest for runs/* resource loaders. Extend useInterval with pauseWhenHidden for background tabs.
1 parent 9cb6fd1 commit f72b6d2

3 files changed

Lines changed: 65 additions & 1 deletion

File tree

apps/webapp/app/hooks/useInterval.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ type UseIntervalOptions = {
66
onLoad?: boolean;
77
onFocus?: boolean;
88
disabled?: boolean;
9+
/** Skip interval ticks while the document tab is hidden */
10+
pauseWhenHidden?: boolean;
911
callback: () => void;
1012
};
1113

@@ -14,6 +16,7 @@ export function useInterval({
1416
onLoad = true,
1517
onFocus = true,
1618
disabled = false,
19+
pauseWhenHidden = false,
1720
callback,
1821
}: UseIntervalOptions) {
1922
// Always keep the latest callback in a ref so the effects below
@@ -28,11 +31,14 @@ export function useInterval({
2831
if (!interval || interval <= 0 || disabled) return;
2932

3033
const intervalId = setInterval(() => {
34+
if (pauseWhenHidden && document.visibilityState !== "visible") {
35+
return;
36+
}
3137
latestCallback.current();
3238
}, interval);
3339

3440
return () => clearInterval(intervalId);
35-
}, [interval, disabled]);
41+
}, [interval, disabled, pauseWhenHidden]);
3642

3743
// On focus
3844
useEffect(() => {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { type TaskRunStatus } from "@trigger.dev/database";
2+
import { isCancellableRunStatus, isFinalRunStatus, isPendingRunStatus } from "~/v3/taskStatus";
3+
4+
type LiveRunRow = {
5+
friendlyId: string;
6+
status: TaskRunStatus;
7+
updatedAt: Date;
8+
startedAt: Date | null;
9+
lockedAt: Date | null;
10+
completedAt: Date | null;
11+
usageDurationMs: bigint | number;
12+
costInCents: number;
13+
baseCostInCents: number;
14+
};
15+
16+
export function mapRunToLiveFields(run: LiveRunRow) {
17+
const hasFinished = isFinalRunStatus(run.status);
18+
const startedAt = run.startedAt ?? run.lockedAt;
19+
20+
return {
21+
friendlyId: run.friendlyId,
22+
status: run.status,
23+
updatedAt: run.updatedAt.toISOString(),
24+
startedAt: startedAt?.toISOString(),
25+
finishedAt: hasFinished ? run.completedAt?.toISOString() ?? run.updatedAt.toISOString() : undefined,
26+
hasFinished,
27+
isCancellable: isCancellableRunStatus(run.status),
28+
isPending: isPendingRunStatus(run.status),
29+
usageDurationMs: Number(run.usageDurationMs),
30+
costInCents: run.costInCents,
31+
baseCostInCents: run.baseCostInCents,
32+
};
33+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { type Params } from "@remix-run/react";
2+
import { findProjectBySlug } from "~/models/project.server";
3+
import { findEnvironmentBySlug } from "~/models/runtimeEnvironment.server";
4+
import { requireUserId } from "~/services/session.server";
5+
import { EnvironmentParamSchema } from "~/utils/pathBuilder";
6+
7+
export async function loadProjectEnvironmentFromRequest(
8+
request: Request,
9+
params: Params<string>
10+
) {
11+
const userId = await requireUserId(request);
12+
const { organizationSlug, projectParam, envParam } = EnvironmentParamSchema.parse(params);
13+
14+
const project = await findProjectBySlug(organizationSlug, projectParam, userId);
15+
if (!project) {
16+
throw new Response(undefined, { status: 404, statusText: "Project not found" });
17+
}
18+
19+
const environment = await findEnvironmentBySlug(project.id, envParam, userId);
20+
if (!environment) {
21+
throw new Response(undefined, { status: 404, statusText: "Environment not found" });
22+
}
23+
24+
return { userId, project, environment };
25+
}

0 commit comments

Comments
 (0)