11import { conform , useForm } from "@conform-to/react" ;
22import { parse } from "@conform-to/zod" ;
33import { 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" ;
125import { useCallback , useEffect , useMemo , useRef , useState } from "react" ;
136import { type UseDataFunctionReturn , useTypedFetcher } from "remix-typedjson" ;
147import { TaskIcon } from "~/assets/icons/TaskIcon" ;
@@ -59,13 +52,22 @@ export function ReplayRunDialog({ runFriendlyId, failedRedirect }: ReplayRunDial
5952}
6053
6154function 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 = { {
0 commit comments