Skip to content

Commit 21dda1a

Browse files
committed
Reload queues and versions on env override
1 parent e0bb5cb commit 21dda1a

File tree

2 files changed

+68
-30
lines changed

2 files changed

+68
-30
lines changed

apps/webapp/app/components/runs/v3/ReplayRunDialog.tsx

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
import { conform, useForm } from "@conform-to/react";
22
import { parse } from "@conform-to/zod";
33
import { DialogClose } from "@radix-ui/react-dialog";
4-
import {
5-
Form,
6-
useActionData,
7-
useFetcher,
8-
useNavigation,
9-
useParams,
10-
useSubmit,
11-
} from "@remix-run/react";
4+
import { Form, useActionData, useNavigation, useParams, useSubmit } from "@remix-run/react";
125
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
136
import { type UseDataFunctionReturn, useTypedFetcher } from "remix-typedjson";
147
import { TaskIcon } from "~/assets/icons/TaskIcon";
@@ -59,13 +52,22 @@ export function ReplayRunDialog({ runFriendlyId, failedRedirect }: ReplayRunDial
5952
}
6053

6154
function ReplayContent({ runFriendlyId, failedRedirect }: ReplayRunDialogProps) {
62-
const fetcher = useTypedFetcher<typeof loader>();
63-
const isLoading = fetcher.state === "loading";
55+
const replayDataFetcher = useTypedFetcher<typeof loader>();
56+
const isLoading = replayDataFetcher.state === "loading";
6457
const queueFetcher = useTypedFetcher<typeof queuesLoader>();
6558

59+
const [environmentIdOverride, setEnvironmentIdOverride] = useState<string | undefined>(undefined);
60+
6661
useEffect(() => {
67-
fetcher.load(`/resources/taskruns/${runFriendlyId}/replay`);
68-
}, [runFriendlyId]);
62+
const searchParams = new URLSearchParams();
63+
if (environmentIdOverride) {
64+
searchParams.set("environmentIdOverride", environmentIdOverride);
65+
}
66+
67+
replayDataFetcher.load(
68+
`/resources/taskruns/${runFriendlyId}/replay?${searchParams.toString()}`
69+
);
70+
}, [runFriendlyId, environmentIdOverride]);
6971

7072
const params = useParams();
7173
useEffect(() => {
@@ -74,13 +76,22 @@ function ReplayContent({ runFriendlyId, failedRedirect }: ReplayRunDialogProps)
7476
searchParams.set("type", "custom");
7577
searchParams.set("per_page", "100");
7678

79+
let envSlug = params.envParam;
80+
81+
if (environmentIdOverride) {
82+
const environmentOverride = replayDataFetcher.data?.environments.find(
83+
(env) => env.id === environmentIdOverride
84+
);
85+
envSlug = environmentOverride?.slug ?? envSlug;
86+
}
87+
7788
queueFetcher.load(
78-
`/resources/orgs/${params.organizationSlug}/projects/${params.projectParam}/env/${
79-
params.envParam
80-
}/queues?${searchParams.toString()}`
89+
`/resources/orgs/${params.organizationSlug}/projects/${
90+
params.projectParam
91+
}/env/${envSlug}/queues?${searchParams.toString()}`
8192
);
8293
}
83-
}, [params.organizationSlug, params.projectParam, params.envParam]);
94+
}, [params.organizationSlug, params.projectParam, params.envParam, environmentIdOverride]);
8495

8596
const customQueues = useMemo(() => {
8697
return queueFetcher.data?.queues ?? [];
@@ -89,16 +100,18 @@ function ReplayContent({ runFriendlyId, failedRedirect }: ReplayRunDialogProps)
89100
return (
90101
<div className="flex flex-1 flex-col overflow-hidden">
91102
<DialogHeader className="px-3">Replay this run</DialogHeader>
92-
{isLoading ? (
93-
<div className="grid place-items-center p-6">
103+
{isLoading && !replayDataFetcher.data ? (
104+
<div className="flex h-full items-center justify-center p-6">
94105
<Spinner />
95106
</div>
96-
) : fetcher.data ? (
107+
) : replayDataFetcher.data ? (
97108
<ReplayForm
98-
replayData={fetcher.data}
109+
replayData={replayDataFetcher.data}
99110
failedRedirect={failedRedirect}
100111
runFriendlyId={runFriendlyId}
101112
customQueues={customQueues}
113+
environmentIdOverride={environmentIdOverride}
114+
setEnvironmentIdOverride={setEnvironmentIdOverride}
102115
/>
103116
) : (
104117
<>Failed to get run data</>
@@ -115,11 +128,15 @@ function ReplayForm({
115128
runFriendlyId,
116129
replayData,
117130
customQueues,
131+
environmentIdOverride,
132+
setEnvironmentIdOverride,
118133
}: {
119134
failedRedirect: string;
120135
runFriendlyId: string;
121136
replayData: UseDataFunctionReturn<typeof loader>;
122137
customQueues: UseDataFunctionReturn<typeof queuesLoader>["queues"];
138+
environmentIdOverride: string | undefined;
139+
setEnvironmentIdOverride: (environment: string) => void;
123140
}) {
124141
const navigation = useNavigation();
125142
const submit = useSubmit();
@@ -304,11 +321,15 @@ function ReplayForm({
304321
dropdownIcon
305322
disabled={replayData.disableVersionSelection}
306323
>
307-
{replayData.latestVersions.map((version, i) => (
308-
<SelectItem key={version} value={i === 0 ? "latest" : version}>
309-
{version} {i === 0 && "(latest)"}
310-
</SelectItem>
311-
))}
324+
{replayData.latestVersions.length === 0 ? (
325+
<SelectItem disabled>No versions available</SelectItem>
326+
) : (
327+
replayData.latestVersions.map((version, i) => (
328+
<SelectItem key={version} value={i === 0 ? "latest" : version}>
329+
{version} {i === 0 && "(latest)"}
330+
</SelectItem>
331+
))
332+
)}
312333
</Select>
313334
{replayData.disableVersionSelection ? (
314335
<Hint>Only the latest version is available in the development environment.</Hint>
@@ -489,6 +510,8 @@ function ReplayForm({
489510
defaultValue={replayData.environment.id}
490511
items={replayData.environments}
491512
dropdownIcon
513+
value={environmentIdOverride}
514+
setValue={setEnvironmentIdOverride}
492515
variant="tertiary/medium"
493516
className="w-fit pl-1"
494517
filter={{

apps/webapp/app/routes/resources.taskruns.$runParam.replay.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,16 @@ const ParamSchema = z.object({
2020
runParam: z.string(),
2121
});
2222

23+
const QuerySchema = z.object({
24+
environmentIdOverride: z.string().optional(),
25+
});
26+
2327
export async function loader({ request, params }: LoaderFunctionArgs) {
2428
const userId = await requireUserId(request);
2529
const { runParam } = ParamSchema.parse(params);
30+
const { environmentIdOverride } = QuerySchema.parse(
31+
Object.fromEntries(new URL(request.url).searchParams)
32+
);
2633

2734
const run = await $replica.taskRun.findFirst({
2835
select: {
@@ -81,16 +88,24 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
8188
throw new Response("Not Found", { status: 404 });
8289
}
8390

84-
const environment = run.project.environments.find((env) => env.id === run.runtimeEnvironmentId);
91+
const runEnvironment = run.project.environments.find(
92+
(env) => env.id === run.runtimeEnvironmentId
93+
);
94+
const environmentOverride = run.project.environments.find(
95+
(env) => env.id === environmentIdOverride
96+
);
97+
const environment = environmentOverride ?? runEnvironment;
8598
if (!environment) {
8699
throw new Response("Environment not found", { status: 404 });
87100
}
88101

89102
const task =
90103
environment.type !== "DEVELOPMENT"
91-
? (await findCurrentWorkerDeployment({ environmentId: environment.id }))?.worker?.tasks.find(
92-
(t) => t.slug === run.taskIdentifier
93-
)
104+
? (
105+
await findCurrentWorkerDeployment({
106+
environmentId: environment.id,
107+
})
108+
)?.worker?.tasks.find((t) => t.slug === run.taskIdentifier)
94109
: await $replica.backgroundWorkerTask.findFirst({
95110
select: {
96111
queueId: true,
@@ -135,7 +150,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
135150

136151
const latestVersions = backgroundWorkers.map((v) => v.version);
137152
const disableVersionSelection = environment.type === "DEVELOPMENT";
138-
const allowArbitraryQueues = backgroundWorkers[0]?.engine === "V1";
153+
const allowArbitraryQueues = backgroundWorkers.at(0)?.engine === "V1";
139154

140155
return typedjson({
141156
concurrencyKey: run.concurrencyKey,

0 commit comments

Comments
 (0)