66 TrashIcon ,
77} from "@heroicons/react/20/solid" ;
88import { DialogDescription } from "@radix-ui/react-dialog" ;
9- import { Form , useLocation } from "@remix-run/react" ;
9+ import { type FetcherWithComponents , Form , useLocation } from "@remix-run/react" ;
1010import { type ReactNode } from "react" ;
1111import { InlineCode } from "~/components/code/InlineCode" ;
1212import { EnvironmentCombo } from "~/components/environments/EnvironmentLabel" ;
@@ -76,9 +76,22 @@ type Props = {
7676 * is rendered somewhere else (e.g. in a sheet on a different page).
7777 */
7878 actionPath ?: string ;
79+ /** When set, Edit calls back instead of navigating to the standalone edit page. */
80+ onEdit ?: ( ) => void ;
81+ /** Submits enable/disable via this fetcher with `_format=json` so the host stays put. */
82+ activeToggleFetcher ?: FetcherWithComponents < unknown > ;
83+ /** Submits delete via this fetcher with `_format=json` so the host stays put. */
84+ deleteFetcher ?: FetcherWithComponents < unknown > ;
7985} ;
8086
81- export function ScheduleInspector ( { schedule, headerActions, actionPath } : Props ) {
87+ export function ScheduleInspector ( {
88+ schedule,
89+ headerActions,
90+ actionPath,
91+ onEdit,
92+ activeToggleFetcher,
93+ deleteFetcher,
94+ } : Props ) {
8295 const location = useLocation ( ) ;
8396 const organization = useOrganization ( ) ;
8497 const project = useProject ( ) ;
@@ -91,7 +104,7 @@ export function ScheduleInspector({ schedule, headerActions, actionPath }: Props
91104 < div
92105 className = { cn (
93106 "grid h-full max-h-full overflow-hidden bg-background-bright" ,
94- isImperative ? "grid-rows-[2.5rem_1fr_3.25rem ]" : "grid-rows-[2.5rem_1fr]"
107+ isImperative ? "grid-rows-[2.5rem_1fr_auto ]" : "grid-rows-[2.5rem_1fr]"
95108 ) }
96109 >
97110 < div className = "mx-3 flex items-center justify-between gap-2 border-b border-grid-dimmed" >
@@ -244,30 +257,38 @@ export function ScheduleInspector({ schedule, headerActions, actionPath }: Props
244257 </ div >
245258 </ div >
246259 { isImperative && (
247- < div className = "flex items-center justify-between gap-2 border-t border-grid-dimmed px-2" >
260+ < div className = "flex items-center justify-between gap-2 border-t border-grid-dimmed px-2 py-2 " >
248261 < div className = "flex items-center gap-2" >
249- < Form method = "post" action = { actionPath } >
250- < Button
251- type = "submit"
252- variant = "tertiary/medium"
253- LeadingIcon = { schedule . active ? BoltSlashIcon : BoltIcon }
254- leadingIconClassName = { schedule . active ? "text-dimmed" : "text-success" }
255- name = "action"
256- value = { schedule . active ? "disable" : "enable" }
257- >
258- { schedule . active ? "Disable" : "Enable" }
259- </ Button >
260- </ Form >
262+ { ( ( ) => {
263+ const ToggleForm = activeToggleFetcher ?. Form ?? Form ;
264+ const isSubmitting = activeToggleFetcher ?. state === "submitting" ;
265+ return (
266+ < ToggleForm method = "post" action = { actionPath } >
267+ { activeToggleFetcher ? < input type = "hidden" name = "_format" value = "json" /> : null }
268+ < Button
269+ type = "submit"
270+ variant = "secondary/small"
271+ LeadingIcon = { schedule . active ? BoltSlashIcon : BoltIcon }
272+ leadingIconClassName = { schedule . active ? "text-dimmed" : "text-success" }
273+ name = "action"
274+ value = { schedule . active ? "disable" : "enable" }
275+ disabled = { isSubmitting }
276+ >
277+ { schedule . active ? "Disable" : "Enable" }
278+ </ Button >
279+ </ ToggleForm >
280+ ) ;
281+ } ) ( ) }
261282 < Dialog >
262283 < DialogTrigger asChild >
263284 < Button
264285 type = "submit"
265- variant = "danger/medium "
286+ variant = "danger/small "
266287 LeadingIcon = { TrashIcon }
267288 name = "action"
268289 value = "delete"
269290 >
270- Delete
291+ Delete…
271292 </ Button >
272293 </ DialogTrigger >
273294 < DialogContent className = "sm:max-w-sm" >
@@ -276,31 +297,45 @@ export function ScheduleInspector({ schedule, headerActions, actionPath }: Props
276297 Are you sure you want to delete this schedule? This can't be reversed.
277298 </ DialogDescription >
278299 < DialogFooter className = "sm:justify-end" >
279- < Form method = "post" action = { actionPath } >
280- < Button
281- type = "submit"
282- variant = "danger/medium"
283- LeadingIcon = { TrashIcon }
284- name = "action"
285- value = "delete"
286- >
287- Delete
288- </ Button >
289- </ Form >
300+ { ( ( ) => {
301+ const DeleteForm = deleteFetcher ?. Form ?? Form ;
302+ const isSubmitting = deleteFetcher ?. state === "submitting" ;
303+ return (
304+ < DeleteForm method = "post" action = { actionPath } >
305+ { deleteFetcher ? < input type = "hidden" name = "_format" value = "json" /> : null }
306+ < Button
307+ type = "submit"
308+ variant = "danger/medium"
309+ LeadingIcon = { TrashIcon }
310+ name = "action"
311+ value = "delete"
312+ disabled = { isSubmitting }
313+ >
314+ Delete
315+ </ Button >
316+ </ DeleteForm >
317+ ) ;
318+ } ) ( ) }
290319 </ DialogFooter >
291320 </ DialogContent >
292321 </ Dialog >
293322 </ div >
294323 < div className = "flex items-center gap-4" >
295- < LinkButton
296- variant = "tertiary/medium"
297- to = { `${ v3EditSchedulePath ( organization , project , environment , schedule ) } ${
298- location . search
299- } `}
300- LeadingIcon = { PencilSquareIcon }
301- >
302- Edit schedule
303- </ LinkButton >
324+ { onEdit ? (
325+ < Button variant = "secondary/small" LeadingIcon = { PencilSquareIcon } onClick = { onEdit } >
326+ Edit schedule…
327+ </ Button >
328+ ) : (
329+ < LinkButton
330+ variant = "secondary/small"
331+ to = { `${ v3EditSchedulePath ( organization , project , environment , schedule ) } ${
332+ location . search
333+ } `}
334+ LeadingIcon = { PencilSquareIcon }
335+ >
336+ Edit schedule…
337+ </ LinkButton >
338+ ) }
304339 </ div >
305340 </ div >
306341 ) }
0 commit comments