mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
feat(logs): add cancel execution to log row context menu (#4130)
* feat(logs): add cancel execution to log row context menu * lint * fix(logs): check success response and use targeted cache invalidation
This commit is contained in:
+12
@@ -22,6 +22,7 @@ interface LogRowContextMenuProps {
|
||||
onOpenPreview: () => void
|
||||
onToggleWorkflowFilter: () => void
|
||||
onClearAllFilters: () => void
|
||||
onCancelExecution: () => void
|
||||
isFilteredByThisWorkflow: boolean
|
||||
hasActiveFilters: boolean
|
||||
}
|
||||
@@ -41,11 +42,13 @@ export const LogRowContextMenu = memo(function LogRowContextMenu({
|
||||
onOpenPreview,
|
||||
onToggleWorkflowFilter,
|
||||
onClearAllFilters,
|
||||
onCancelExecution,
|
||||
isFilteredByThisWorkflow,
|
||||
hasActiveFilters,
|
||||
}: LogRowContextMenuProps) {
|
||||
const hasExecutionId = Boolean(log?.executionId)
|
||||
const hasWorkflow = Boolean(log?.workflow?.id || log?.workflowId)
|
||||
const isRunning = log?.status === 'running' && hasExecutionId && hasWorkflow
|
||||
|
||||
return (
|
||||
<DropdownMenu open={isOpen} onOpenChange={(open) => !open && onClose()} modal={false}>
|
||||
@@ -69,6 +72,15 @@ export const LogRowContextMenu = memo(function LogRowContextMenu({
|
||||
sideOffset={4}
|
||||
onCloseAutoFocus={(e) => e.preventDefault()}
|
||||
>
|
||||
{isRunning && (
|
||||
<>
|
||||
<DropdownMenuItem onSelect={onCancelExecution} className='text-destructive'>
|
||||
<X />
|
||||
Cancel Execution
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
)}
|
||||
<DropdownMenuItem disabled={!hasExecutionId} onSelect={onCopyExecutionId}>
|
||||
<Copy />
|
||||
Copy Execution ID
|
||||
|
||||
@@ -54,6 +54,7 @@ import { getBlock } from '@/blocks/registry'
|
||||
import { useFolderMap, useFolders } from '@/hooks/queries/folders'
|
||||
import {
|
||||
prefetchLogDetail,
|
||||
useCancelExecution,
|
||||
useDashboardStats,
|
||||
useLogDetail,
|
||||
useLogsList,
|
||||
@@ -534,6 +535,17 @@ export default function Logs() {
|
||||
}
|
||||
}, [contextMenuLog])
|
||||
|
||||
const cancelExecution = useCancelExecution()
|
||||
|
||||
const handleCancelExecution = useCallback(() => {
|
||||
const workflowId = contextMenuLog?.workflow?.id || contextMenuLog?.workflowId
|
||||
const executionId = contextMenuLog?.executionId
|
||||
if (workflowId && executionId) {
|
||||
cancelExecution.mutate({ workflowId, executionId })
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [contextMenuLog])
|
||||
|
||||
const contextMenuWorkflowId = contextMenuLog?.workflow?.id || contextMenuLog?.workflowId
|
||||
const isFilteredByThisWorkflow = Boolean(
|
||||
contextMenuWorkflowId && workflowIds.length === 1 && workflowIds[0] === contextMenuWorkflowId
|
||||
@@ -1178,6 +1190,7 @@ export default function Logs() {
|
||||
onCopyLink={handleCopyLink}
|
||||
onOpenWorkflow={handleOpenWorkflow}
|
||||
onOpenPreview={handleOpenPreview}
|
||||
onCancelExecution={handleCancelExecution}
|
||||
onToggleWorkflowFilter={handleToggleWorkflowFilter}
|
||||
onClearAllFilters={handleClearAllFilters}
|
||||
isFilteredByThisWorkflow={isFilteredByThisWorkflow}
|
||||
|
||||
@@ -2,7 +2,9 @@ import {
|
||||
keepPreviousData,
|
||||
type QueryClient,
|
||||
useInfiniteQuery,
|
||||
useMutation,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
} from '@tanstack/react-query'
|
||||
import { getEndDateFromTimeRange, getStartDateFromTimeRange } from '@/lib/logs/filters'
|
||||
import { parseQuery, queryToApiParams } from '@/lib/logs/query-parser'
|
||||
@@ -273,3 +275,29 @@ export function useExecutionSnapshot(executionId: string | undefined) {
|
||||
staleTime: 5 * 60 * 1000, // 5 minutes - execution snapshots don't change
|
||||
})
|
||||
}
|
||||
|
||||
export function useCancelExecution() {
|
||||
const queryClient = useQueryClient()
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
workflowId,
|
||||
executionId,
|
||||
}: {
|
||||
workflowId: string
|
||||
executionId: string
|
||||
}) => {
|
||||
const res = await fetch(`/api/workflows/${workflowId}/executions/${executionId}/cancel`, {
|
||||
method: 'POST',
|
||||
})
|
||||
if (!res.ok) throw new Error('Failed to cancel execution')
|
||||
const data = await res.json()
|
||||
if (!data.success) throw new Error('Failed to cancel execution')
|
||||
return data
|
||||
},
|
||||
onSettled: () => {
|
||||
queryClient.invalidateQueries({ queryKey: logKeys.lists() })
|
||||
queryClient.invalidateQueries({ queryKey: logKeys.details() })
|
||||
queryClient.invalidateQueries({ queryKey: [...logKeys.all, 'stats'] })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user