File tree Expand file tree Collapse file tree 3 files changed +53
-0
lines changed
app/workspace/[workspaceId]/logs Expand file tree Collapse file tree 3 files changed +53
-0
lines changed Original file line number Diff line number Diff line change @@ -22,6 +22,7 @@ interface LogRowContextMenuProps {
2222 onOpenPreview : ( ) => void
2323 onToggleWorkflowFilter : ( ) => void
2424 onClearAllFilters : ( ) => void
25+ onCancelExecution : ( ) => void
2526 isFilteredByThisWorkflow : boolean
2627 hasActiveFilters : boolean
2728}
@@ -41,11 +42,13 @@ export const LogRowContextMenu = memo(function LogRowContextMenu({
4142 onOpenPreview,
4243 onToggleWorkflowFilter,
4344 onClearAllFilters,
45+ onCancelExecution,
4446 isFilteredByThisWorkflow,
4547 hasActiveFilters,
4648} : LogRowContextMenuProps ) {
4749 const hasExecutionId = Boolean ( log ?. executionId )
4850 const hasWorkflow = Boolean ( log ?. workflow ?. id || log ?. workflowId )
51+ const isRunning = log ?. status === 'running' && hasExecutionId && hasWorkflow
4952
5053 return (
5154 < DropdownMenu open = { isOpen } onOpenChange = { ( open ) => ! open && onClose ( ) } modal = { false } >
@@ -69,6 +72,15 @@ export const LogRowContextMenu = memo(function LogRowContextMenu({
6972 sideOffset = { 4 }
7073 onCloseAutoFocus = { ( e ) => e . preventDefault ( ) }
7174 >
75+ { isRunning && (
76+ < >
77+ < DropdownMenuItem onSelect = { onCancelExecution } className = 'text-destructive' >
78+ < X />
79+ Cancel Execution
80+ </ DropdownMenuItem >
81+ < DropdownMenuSeparator />
82+ </ >
83+ ) }
7284 < DropdownMenuItem disabled = { ! hasExecutionId } onSelect = { onCopyExecutionId } >
7385 < Copy />
7486 Copy Execution ID
Original file line number Diff line number Diff line change @@ -54,6 +54,7 @@ import { getBlock } from '@/blocks/registry'
5454import { useFolderMap , useFolders } from '@/hooks/queries/folders'
5555import {
5656 prefetchLogDetail ,
57+ useCancelExecution ,
5758 useDashboardStats ,
5859 useLogDetail ,
5960 useLogsList ,
@@ -534,6 +535,17 @@ export default function Logs() {
534535 }
535536 } , [ contextMenuLog ] )
536537
538+ const cancelExecution = useCancelExecution ( )
539+
540+ const handleCancelExecution = useCallback ( ( ) => {
541+ const workflowId = contextMenuLog ?. workflow ?. id || contextMenuLog ?. workflowId
542+ const executionId = contextMenuLog ?. executionId
543+ if ( workflowId && executionId ) {
544+ cancelExecution . mutate ( { workflowId, executionId } )
545+ }
546+ // eslint-disable-next-line react-hooks/exhaustive-deps
547+ } , [ contextMenuLog ] )
548+
537549 const contextMenuWorkflowId = contextMenuLog ?. workflow ?. id || contextMenuLog ?. workflowId
538550 const isFilteredByThisWorkflow = Boolean (
539551 contextMenuWorkflowId && workflowIds . length === 1 && workflowIds [ 0 ] === contextMenuWorkflowId
@@ -1178,6 +1190,7 @@ export default function Logs() {
11781190 onCopyLink = { handleCopyLink }
11791191 onOpenWorkflow = { handleOpenWorkflow }
11801192 onOpenPreview = { handleOpenPreview }
1193+ onCancelExecution = { handleCancelExecution }
11811194 onToggleWorkflowFilter = { handleToggleWorkflowFilter }
11821195 onClearAllFilters = { handleClearAllFilters }
11831196 isFilteredByThisWorkflow = { isFilteredByThisWorkflow }
Original file line number Diff line number Diff line change 22 keepPreviousData ,
33 type QueryClient ,
44 useInfiniteQuery ,
5+ useMutation ,
56 useQuery ,
7+ useQueryClient ,
68} from '@tanstack/react-query'
79import { getEndDateFromTimeRange , getStartDateFromTimeRange } from '@/lib/logs/filters'
810import { parseQuery , queryToApiParams } from '@/lib/logs/query-parser'
@@ -273,3 +275,29 @@ export function useExecutionSnapshot(executionId: string | undefined) {
273275 staleTime : 5 * 60 * 1000 , // 5 minutes - execution snapshots don't change
274276 } )
275277}
278+
279+ export function useCancelExecution ( ) {
280+ const queryClient = useQueryClient ( )
281+ return useMutation ( {
282+ mutationFn : async ( {
283+ workflowId,
284+ executionId,
285+ } : {
286+ workflowId : string
287+ executionId : string
288+ } ) => {
289+ const res = await fetch ( `/api/workflows/${ workflowId } /executions/${ executionId } /cancel` , {
290+ method : 'POST' ,
291+ } )
292+ if ( ! res . ok ) throw new Error ( 'Failed to cancel execution' )
293+ const data = await res . json ( )
294+ if ( ! data . success ) throw new Error ( 'Failed to cancel execution' )
295+ return data
296+ } ,
297+ onSettled : ( ) => {
298+ queryClient . invalidateQueries ( { queryKey : logKeys . lists ( ) } )
299+ queryClient . invalidateQueries ( { queryKey : logKeys . details ( ) } )
300+ queryClient . invalidateQueries ( { queryKey : [ ...logKeys . all , 'stats' ] } )
301+ } ,
302+ } )
303+ }
You can’t perform that action at this time.
0 commit comments