diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/log-details.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/log-details.tsx index ec50a5bf08..c8a485a2ef 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/log-details.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/log-details.tsx @@ -266,6 +266,8 @@ interface LogDetailsProps { hasPrev?: boolean /** Callback to retry a failed execution */ onRetryExecution?: () => void + /** Whether a retry is currently in progress */ + isRetryPending?: boolean } /** @@ -283,6 +285,7 @@ export const LogDetails = memo(function LogDetails({ hasNext = false, hasPrev = false, onRetryExecution, + isRetryPending = false, }: LogDetailsProps) { const [isExecutionSnapshotOpen, setIsExecutionSnapshotOpen] = useState(false) const scrollAreaRef = useRef(null) @@ -399,6 +402,7 @@ export const LogDetails = memo(function LogDetails({ variant='ghost' className='!p-1' onClick={() => onRetryExecution?.()} + disabled={isRetryPending} aria-label='Retry execution' > diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/log-row-context-menu/log-row-context-menu.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/log-row-context-menu/log-row-context-menu.tsx index 2c46371550..01b867e25e 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/components/log-row-context-menu/log-row-context-menu.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/components/log-row-context-menu/log-row-context-menu.tsx @@ -24,6 +24,7 @@ interface LogRowContextMenuProps { onClearAllFilters: () => void onCancelExecution: () => void onRetryExecution: () => void + isRetryPending?: boolean isFilteredByThisWorkflow: boolean hasActiveFilters: boolean } @@ -45,6 +46,7 @@ export const LogRowContextMenu = memo(function LogRowContextMenu({ onClearAllFilters, onCancelExecution, onRetryExecution, + isRetryPending = false, isFilteredByThisWorkflow, hasActiveFilters, }: LogRowContextMenuProps) { @@ -78,9 +80,9 @@ export const LogRowContextMenu = memo(function LogRowContextMenu({ > {isRetryable && ( <> - + - Retry + {isRetryPending ? 'Retrying...' : 'Retry'} diff --git a/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx b/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx index 393772b04e..33bc43e372 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx @@ -821,6 +821,7 @@ export default function Logs() { hasNext={selectedLogIndex < sortedLogs.length - 1} hasPrev={selectedLogIndex > 0} onRetryExecution={handleRetrySidebarExecution} + isRetryPending={retryExecution.isPending} /> ), [ @@ -830,6 +831,7 @@ export default function Logs() { handleNavigateNext, handleNavigatePrev, handleRetrySidebarExecution, + retryExecution.isPending, selectedLogIndex, sortedLogs.length, ] @@ -1231,6 +1233,7 @@ export default function Logs() { onOpenPreview={handleOpenPreview} onCancelExecution={handleCancelExecution} onRetryExecution={handleRetryExecution} + isRetryPending={retryExecution.isPending} onToggleWorkflowFilter={handleToggleWorkflowFilter} onClearAllFilters={handleClearAllFilters} isFilteredByThisWorkflow={isFilteredByThisWorkflow} diff --git a/apps/sim/app/workspace/[workspaceId]/logs/utils.ts b/apps/sim/app/workspace/[workspaceId]/logs/utils.ts index 5a38526e39..43fd35be5f 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/utils.ts +++ b/apps/sim/app/workspace/[workspaceId]/logs/utils.ts @@ -438,12 +438,19 @@ export function extractRetryInput(log: WorkflowLog): unknown | undefined { } const executionState = execData.executionState as - | { blockStates?: Record } + | { + blockStates?: Record< + string, + { output?: unknown; executed?: boolean; executionTime?: number } + > + } | undefined if (!executionState?.blockStates) return undefined + // Starter/trigger blocks are pre-populated with executed: false and executionTime: 0, + // which distinguishes them from blocks that actually ran during execution. for (const state of Object.values(executionState.blockStates)) { - if (state.output && typeof state.output === 'object' && 'input' in state.output) { + if (state.executed === false && state.executionTime === 0 && state.output != null) { return state.output } } diff --git a/apps/sim/lib/logs/execution/logger.ts b/apps/sim/lib/logs/execution/logger.ts index acca8db01c..f7b298a131 100644 --- a/apps/sim/lib/logs/execution/logger.ts +++ b/apps/sim/lib/logs/execution/logger.ts @@ -372,6 +372,9 @@ export class ExecutionLogger implements IExecutionLoggerService { ? Math.max(0, Math.round(rawDurationMs)) : 0 + const redactedWorkflowInput = + workflowInput !== undefined ? redactApiKeys(filterForDisplay(workflowInput)) : undefined + const completedExecutionData = this.buildCompletedExecutionData({ existingExecutionData, traceSpans: redactedTraceSpans, @@ -380,7 +383,7 @@ export class ExecutionLogger implements IExecutionLoggerService { completionFailure, executionCost, executionState, - workflowInput, + workflowInput: redactedWorkflowInput, }) const [updatedLog] = await db