11import { BeakerIcon , BookOpenIcon } from "@heroicons/react/24/solid" ;
2- import { type MetaFunction , useNavigation , useRevalidator } from "@remix-run/react" ;
2+ import { type MetaFunction , useLocation , useNavigation , useRevalidator } from "@remix-run/react" ;
33import { type LoaderFunctionArgs } from "@remix-run/server-runtime" ;
4- import { Suspense } from "react" ;
4+ import { Suspense , useState } from "react" ;
55import {
66 TypedAwait ,
77 typeddefer ,
@@ -56,7 +56,6 @@ import { cn } from "~/utils/cn";
5656import {
5757 docsPath ,
5858 EnvironmentParamSchema ,
59- v3CreateBulkActionPath ,
6059 v3ProjectPath ,
6160 v3TestPath ,
6261 v3TestTaskPath ,
@@ -65,8 +64,11 @@ import { throwNotFound } from "~/utils/httpErrors";
6564import { ListPagination } from "../../components/ListPagination" ;
6665import { CreateBulkActionInspector } from "../resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.bulkaction" ;
6766import { Callout } from "~/components/primitives/Callout" ;
67+ import { isRunsListLoading , shouldRevalidateRunsList } from "./shouldRevalidateRunsList" ;
6868import { useRunsLiveReload } from "./useRunsLiveReload" ;
6969
70+ export { shouldRevalidateRunsList as shouldRevalidate } ;
71+
7072export const meta : MetaFunction = ( ) => {
7173 return [
7274 {
@@ -209,8 +211,9 @@ function RunsList({
209211 filters : TaskRunListSearchFilters ;
210212} ) {
211213 const revalidator = useRevalidator ( ) ;
214+ const location = useLocation ( ) ;
212215 const navigation = useNavigation ( ) ;
213- const isLoading = navigation . state !== "idle" ;
216+ const isLoading = isRunsListLoading ( navigation , location . search ) ;
214217 const organization = useOrganization ( ) ;
215218 const project = useProject ( ) ;
216219 const environment = useEnvironment ( ) ;
@@ -244,7 +247,7 @@ function RunsList({
244247 shortcut : { key : "r" } ,
245248 action : ( e ) => {
246249 replace ( {
247- bulkInspector : "true " ,
250+ bulkInspector : "show " ,
248251 action : "replay" ,
249252 mode : selectedItems . size > 0 ? "selected" : undefined ,
250253 } ) ;
@@ -254,14 +257,21 @@ function RunsList({
254257 shortcut : { key : "c" } ,
255258 action : ( e ) => {
256259 replace ( {
257- bulkInspector : "true " ,
260+ bulkInspector : "show " ,
258261 action : "cancel" ,
259262 mode : selectedItems . size > 0 ? "selected" : undefined ,
260263 } ) ;
261264 } ,
262265 } ) ;
263266
264267 const isShowingBulkActionInspector = has ( "bulkInspector" ) && list . hasAnyRuns ;
268+ const [ isBulkInspectorPanelCollapsed , setIsBulkInspectorPanelCollapsed ] = useState (
269+ ! isShowingBulkActionInspector
270+ ) ;
271+ // Keep content mounted until onCollapseChange reports the panel is fully collapsed.
272+ const showBulkInspectorContent =
273+ isShowingBulkActionInspector || ! isBulkInspectorPanelCollapsed ;
274+
265275 return (
266276 < ResizablePanelGroup orientation = "horizontal" className = "max-h-full" >
267277 < ResizablePanel id = "runs-main" min = { "100px" } >
@@ -310,39 +320,41 @@ function RunsList({
310320 </ Button >
311321 </ span >
312322 ) }
313- { ! isShowingBulkActionInspector && (
314- < LinkButton
315- variant = "secondary/small"
316- to = { v3CreateBulkActionPath (
317- organization ,
318- project ,
319- environment ,
320- filters ,
321- selectedItems . size > 0 ? "selected" : undefined
322- ) }
323- LeadingIcon = { ListCheckedIcon }
324- className = { selectedItems . size > 0 ? "pr-1" : undefined }
325- tooltip = {
326- < div className = "-mr-1 flex items-center gap-3 text-xs text-text-dimmed" >
327- < div className = "flex items-center gap-0.5" >
328- < span > Replay</ span >
329- < ShortcutKey shortcut = { { key : "r" } } variant = { "small" } />
330- </ div >
331- < div className = "flex items-center gap-0.5" >
332- < span > Cancel</ span >
333- < ShortcutKey shortcut = { { key : "c" } } variant = { "small" } />
334- </ div >
323+ { /* Stay mounted while the inspector is open to avoid toolbar layout shift. */ }
324+ < Button
325+ variant = "secondary/small"
326+ disabled = { isShowingBulkActionInspector }
327+ onClick = { ( ) =>
328+ replace ( {
329+ bulkInspector : "show" ,
330+ mode : selectedItems . size > 0 ? "selected" : undefined ,
331+ } )
332+ }
333+ LeadingIcon = { ListCheckedIcon }
334+ className = { cn (
335+ selectedItems . size > 0 ? "pr-1" : undefined ,
336+ isShowingBulkActionInspector && "pointer-events-none invisible"
337+ ) }
338+ tooltip = {
339+ < div className = "-mr-1 flex items-center gap-3 text-xs text-text-dimmed" >
340+ < div className = "flex items-center gap-0.5" >
341+ < span > Replay</ span >
342+ < ShortcutKey shortcut = { { key : "r" } } variant = { "small" } />
335343 </ div >
336- }
337- >
338- < span className = "flex items-center gap-x-1 whitespace-nowrap text-text-bright" >
339- < span > Bulk action</ span >
340- { selectedItems . size > 0 && (
341- < Badge variant = "rounded" > { selectedItems . size } </ Badge >
342- ) }
343- </ span >
344- </ LinkButton >
345- ) }
344+ < div className = "flex items-center gap-0.5" >
345+ < span > Cancel</ span >
346+ < ShortcutKey shortcut = { { key : "c" } } variant = { "small" } />
347+ </ div >
348+ </ div >
349+ }
350+ >
351+ < span className = "flex items-center gap-x-1 whitespace-nowrap text-text-bright" >
352+ < span > Bulk action</ span >
353+ { selectedItems . size > 0 && (
354+ < Badge variant = "rounded" > { selectedItems . size } </ Badge >
355+ ) }
356+ </ span >
357+ </ Button >
346358 < ListPagination list = { list } />
347359 </ div >
348360 </ div >
@@ -374,12 +386,12 @@ function RunsList({
374386 className = "overflow-hidden"
375387 collapsible
376388 collapsed = { ! isShowingBulkActionInspector }
377- onCollapseChange = { ( ) => { } }
389+ onCollapseChange = { setIsBulkInspectorPanelCollapsed }
378390 collapsedSize = "0px"
379391 collapseAnimation = { RESIZABLE_PANEL_ANIMATION }
380392 >
381393 < div className = "h-full" style = { { minWidth : 400 } } >
382- { isShowingBulkActionInspector && (
394+ { showBulkInspectorContent && (
383395 < CreateBulkActionInspector
384396 filters = { filters }
385397 selectedItems = { selectedItems }
0 commit comments