11import { BeakerIcon , BookOpenIcon } from "@heroicons/react/24/solid" ;
22import { type MetaFunction , 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 ,
@@ -39,6 +39,7 @@ import { $replica } from "~/db.server";
3939import { useEnvironment } from "~/hooks/useEnvironment" ;
4040import { useOrganization } from "~/hooks/useOrganizations" ;
4141import { useProject } from "~/hooks/useProject" ;
42+ import { useOptimisticLocation } from "~/hooks/useOptimisticLocation" ;
4243import { useSearchParams } from "~/hooks/useSearchParam" ;
4344import { useShortcutKeys } from "~/hooks/useShortcutKeys" ;
4445import { redirectWithErrorMessage } from "~/models/message.server" ;
@@ -56,7 +57,6 @@ import { cn } from "~/utils/cn";
5657import {
5758 docsPath ,
5859 EnvironmentParamSchema ,
59- v3CreateBulkActionPath ,
6060 v3ProjectPath ,
6161 v3TestPath ,
6262 v3TestTaskPath ,
@@ -65,8 +65,11 @@ import { throwNotFound } from "~/utils/httpErrors";
6565import { ListPagination } from "../../components/ListPagination" ;
6666import { CreateBulkActionInspector } from "../resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.bulkaction" ;
6767import { Callout } from "~/components/primitives/Callout" ;
68+ import { isRunsListLoading , shouldRevalidateRunsList } from "./shouldRevalidateRunsList" ;
6869import { useRunsLiveReload } from "./useRunsLiveReload" ;
6970
71+ export { shouldRevalidateRunsList as shouldRevalidate } ;
72+
7073export const meta : MetaFunction = ( ) => {
7174 return [
7275 {
@@ -209,8 +212,9 @@ function RunsList({
209212 filters : TaskRunListSearchFilters ;
210213} ) {
211214 const revalidator = useRevalidator ( ) ;
215+ const location = useOptimisticLocation ( ) ;
212216 const navigation = useNavigation ( ) ;
213- const isLoading = navigation . state !== "idle" ;
217+ const isLoading = isRunsListLoading ( navigation , location . search ) ;
214218 const organization = useOrganization ( ) ;
215219 const project = useProject ( ) ;
216220 const environment = useEnvironment ( ) ;
@@ -244,7 +248,7 @@ function RunsList({
244248 shortcut : { key : "r" } ,
245249 action : ( e ) => {
246250 replace ( {
247- bulkInspector : "true " ,
251+ bulkInspector : "show " ,
248252 action : "replay" ,
249253 mode : selectedItems . size > 0 ? "selected" : undefined ,
250254 } ) ;
@@ -254,14 +258,21 @@ function RunsList({
254258 shortcut : { key : "c" } ,
255259 action : ( e ) => {
256260 replace ( {
257- bulkInspector : "true " ,
261+ bulkInspector : "show " ,
258262 action : "cancel" ,
259263 mode : selectedItems . size > 0 ? "selected" : undefined ,
260264 } ) ;
261265 } ,
262266 } ) ;
263267
264268 const isShowingBulkActionInspector = has ( "bulkInspector" ) && list . hasAnyRuns ;
269+ const [ isBulkInspectorPanelCollapsed , setIsBulkInspectorPanelCollapsed ] = useState (
270+ ! isShowingBulkActionInspector
271+ ) ;
272+ // Keep content mounted until onCollapseChange reports the panel is fully collapsed.
273+ const showBulkInspectorContent =
274+ isShowingBulkActionInspector || ! isBulkInspectorPanelCollapsed ;
275+
265276 return (
266277 < ResizablePanelGroup orientation = "horizontal" className = "max-h-full" >
267278 < ResizablePanel id = "runs-main" min = { "100px" } >
@@ -310,39 +321,39 @@ function RunsList({
310321 </ Button >
311322 </ span >
312323 ) }
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 >
324+ < Button
325+ variant = "secondary/small"
326+ onClick = { ( ) =>
327+ replace ( {
328+ bulkInspector : "show" ,
329+ mode : selectedItems . size > 0 ? "selected" : undefined ,
330+ } )
331+ }
332+ LeadingIcon = { ListCheckedIcon }
333+ className = { cn (
334+ selectedItems . size > 0 ? "pr-1" : undefined ,
335+ isShowingBulkActionInspector && "pointer-events-none invisible"
336+ ) }
337+ tooltip = {
338+ < div className = "-mr-1 flex items-center gap-3 text-xs text-text-dimmed" >
339+ < div className = "flex items-center gap-0.5" >
340+ < span > Replay</ span >
341+ < ShortcutKey shortcut = { { key : "r" } } variant = { "small" } />
335342 </ 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- ) }
343+ < div className = "flex items-center gap-0.5" >
344+ < span > Cancel</ span >
345+ < ShortcutKey shortcut = { { key : "c" } } variant = { "small" } />
346+ </ div >
347+ </ div >
348+ }
349+ >
350+ < span className = "flex items-center gap-x-1 whitespace-nowrap text-text-bright" >
351+ < span > Bulk action</ span >
352+ { selectedItems . size > 0 && (
353+ < Badge variant = "rounded" > { selectedItems . size } </ Badge >
354+ ) }
355+ </ span >
356+ </ Button >
346357 < ListPagination list = { list } />
347358 </ div >
348359 </ div >
@@ -374,12 +385,12 @@ function RunsList({
374385 className = "overflow-hidden"
375386 collapsible
376387 collapsed = { ! isShowingBulkActionInspector }
377- onCollapseChange = { ( ) => { } }
388+ onCollapseChange = { setIsBulkInspectorPanelCollapsed }
378389 collapsedSize = "0px"
379390 collapseAnimation = { RESIZABLE_PANEL_ANIMATION }
380391 >
381392 < div className = "h-full" style = { { minWidth : 400 } } >
382- { isShowingBulkActionInspector && (
393+ { showBulkInspectorContent && (
383394 < CreateBulkActionInspector
384395 filters = { filters }
385396 selectedItems = { selectedItems }
0 commit comments