From a1ed1192b8d049667b64d96a2c9aa9d71e6814d7 Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Sat, 16 Aug 2025 14:57:38 -0700 Subject: [PATCH] fix(logs-sidebar): remove message and fix race condition for quickly switching b/w logs --- .../logs/components/sidebar/sidebar.tsx | 25 +++++++++++++----- .../app/workspace/[workspaceId]/logs/logs.tsx | 26 ++++++++++++------- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/sidebar/sidebar.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/sidebar/sidebar.tsx index a4f78226a99..214772865d2 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/components/sidebar/sidebar.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/components/sidebar/sidebar.tsx @@ -1,7 +1,7 @@ 'use client' import { useEffect, useMemo, useRef, useState } from 'react' -import { ChevronDown, ChevronUp, Eye, X } from 'lucide-react' +import { ChevronDown, ChevronUp, Eye, Loader2, X } from 'lucide-react' import { Button } from '@/components/ui/button' import { CopyButton } from '@/components/ui/copy-button' import { ScrollArea } from '@/components/ui/scroll-area' @@ -209,6 +209,15 @@ export function Sidebar({ } }, [log?.id]) + const isLoadingDetails = useMemo(() => { + if (!log) return false + // Only show while we expect details to arrive (has executionId) + if (!log.executionId) return false + const hasEnhanced = !!log.executionData?.enhanced + const hasAnyDetails = hasEnhanced || !!log.cost || Array.isArray(log.executionData?.traceSpans) + return !hasAnyDetails + }, [log]) + const formattedContent = useMemo(() => { if (!log) return null @@ -476,6 +485,14 @@ export function Sidebar({ )} + {/* Suspense while details load (positioned after summary fields) */} + {isLoadingDetails && ( +
+ + Loading details… +
+ )} + {/* Files */} {log.files && log.files.length > 0 && (
@@ -527,11 +544,7 @@ export function Sidebar({
)} - {/* Message Content */} -
-

Message

-
{formattedContent}
-
+ {/* end suspense */} {/* Trace Spans (if available and this is a workflow execution log) */} {isWorkflowExecutionLog && log.executionData?.traceSpans && ( diff --git a/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx b/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx index 516ac058266..68a46a7d9ee 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx @@ -85,8 +85,10 @@ export default function Logs() { const [selectedLog, setSelectedLog] = useState(null) const [selectedLogIndex, setSelectedLogIndex] = useState(-1) const [isSidebarOpen, setIsSidebarOpen] = useState(false) + const [isDetailsLoading, setIsDetailsLoading] = useState(false) const detailsCacheRef = useRef>(new Map()) const detailsAbortRef = useRef(null) + const currentDetailsIdRef = useRef(null) const selectedRowRef = useRef(null) const loaderRef = useRef(null) const scrollContainerRef = useRef(null) @@ -118,6 +120,7 @@ export default function Logs() { const index = logs.findIndex((l) => l.id === log.id) setSelectedLogIndex(index) setIsSidebarOpen(true) + setIsDetailsLoading(true) // Fetch details for current, previous, and next concurrently with cache const currentId = log.id @@ -134,24 +137,26 @@ export default function Logs() { } const controller = new AbortController() detailsAbortRef.current = controller + currentDetailsIdRef.current = currentId const idsToFetch: Array<{ id: string; merge: boolean }> = [] - if (currentId && !detailsCacheRef.current.has(currentId)) - idsToFetch.push({ id: currentId, merge: true }) + const cachedCurrent = currentId ? detailsCacheRef.current.get(currentId) : undefined + if (currentId && !cachedCurrent) idsToFetch.push({ id: currentId, merge: true }) if (prevId && !detailsCacheRef.current.has(prevId)) idsToFetch.push({ id: prevId, merge: false }) if (nextId && !detailsCacheRef.current.has(nextId)) idsToFetch.push({ id: nextId, merge: false }) - if (idsToFetch.length === 0) { - const cached = detailsCacheRef.current.get(currentId) - if (cached) { - setSelectedLog((prev) => - prev && prev.id === currentId ? ({ ...(prev as any), ...(cached as any) } as any) : prev - ) - } - return + // Merge cached current immediately + if (cachedCurrent) { + setSelectedLog((prev) => + prev && prev.id === currentId + ? ({ ...(prev as any), ...(cachedCurrent as any) } as any) + : prev + ) + setIsDetailsLoading(false) } + if (idsToFetch.length === 0) return Promise.all( idsToFetch.map(async ({ id, merge }) => { @@ -166,6 +171,7 @@ export default function Logs() { setSelectedLog((prev) => prev && prev.id === id ? ({ ...(prev as any), ...(detailed as any) } as any) : prev ) + if (currentDetailsIdRef.current === id) setIsDetailsLoading(false) } } } catch (e: any) {