diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/dashboard.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/dashboard.tsx
index a5da603a7c..fa3f683bdd 100644
--- a/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/dashboard.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/dashboard.tsx
@@ -289,9 +289,19 @@ export default function Dashboard({
const executions = metricsQuery.data?.workflows ?? []
const aggregateSegments = metricsQuery.data?.aggregateSegments ?? []
- const loading = metricsQuery.isLoading
const error = metricsQuery.error?.message ?? null
+ /**
+ * Loading state logic using TanStack Query best practices:
+ * - isPending: true when there's no cached data (initial load only)
+ * - isFetching: true when any fetch is in progress
+ * - isPlaceholderData: true when showing stale data from keepPreviousData
+ *
+ * We only show skeleton on initial load (isPending + no data).
+ * For subsequent fetches, keepPreviousData shows stale content while fetching.
+ */
+ const showSkeleton = metricsQuery.isPending && !metricsQuery.data
+
// Check if any filters are actually applied
const hasActiveFilters = useMemo(
() =>
@@ -747,7 +757,7 @@ export default function Dashboard({
}
}, [refreshTrigger])
- if (loading) {
+ if (showSkeleton) {
return
}
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx b/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx
index a45336609d..c8bb71a155 100644
--- a/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx
@@ -408,215 +408,216 @@ export default function Logs() {
/>
- {/* Dashboard view */}
- {isDashboardView && (
-
-
-
- )}
+ {/* Dashboard view - always mounted to preserve state and query cache */}
+
+
+
{/* Main content area with table - only show in logs view */}
- {!isDashboardView && (
-
- {/* Table container */}
-
- {/* Table header */}
-
-
-
- Date
-
-
- Time
-
-
- Status
-
-
- Workflow
-
-
- Cost
-
-
- Trigger
-
-
- Duration
-
-
-
-
- {/* Table body - scrollable */}
-
- {logsQuery.isLoading && !logsQuery.data ? (
-
-
-
- Loading logs...
-
-
- ) : logsQuery.isError ? (
-
-
-
-
- Error: {logsQuery.error?.message || 'Failed to load logs'}
-
-
-
- ) : logs.length === 0 ? (
-
- ) : (
-
- {logs.map((log) => {
- const formattedDate = formatDate(log.createdAt)
- const isSelected = selectedLog?.id === log.id
- const baseLevel = (log.level || 'info').toLowerCase()
- const isError = baseLevel === 'error'
- const isPending = !isError && log.hasPendingPause === true
- const isRunning = !isError && !isPending && log.duration === null
-
- return (
-
handleLogClick(log)}
- >
-
- {/* Date */}
-
- {formattedDate.compactDate}
-
-
- {/* Time */}
-
- {formattedDate.compactTime}
-
-
- {/* Status */}
-
-
-
-
- {/* Workflow */}
-
-
-
- {log.workflow?.name || 'Unknown'}
-
-
-
- {/* Cost */}
-
- {typeof log.cost?.total === 'number'
- ? `$${log.cost.total.toFixed(4)}`
- : '—'}
-
-
- {/* Trigger */}
-
- {log.trigger ? (
-
- ) : (
-
- —
-
- )}
-
-
- {/* Duration */}
-
-
- {formatDuration(log.duration) || '—'}
-
-
-
-
- {/* Resume Link */}
- {isPending &&
- log.executionId &&
- (log.workflow?.id || log.workflowId) && (
-
e.stopPropagation()}
- >
-
-
- )}
-
- )
- })}
-
- {/* Infinite scroll loader */}
- {logsQuery.hasNextPage && (
-
-
- {logsQuery.isFetchingNextPage ? (
- <>
-
- Loading more...
- >
- ) : (
- Scroll to load more
- )}
-
-
- )}
-
- )}
+
+ {/* Table container */}
+
+ {/* Table header */}
+
+
+
+ Date
+
+
+ Time
+
+
+ Status
+
+
+ Workflow
+
+
+ Cost
+
+
+ Trigger
+
+
+ Duration
+
- {/* Log Details - rendered inside table container */}
-
0}
- />
+ {/* Table body - scrollable */}
+
+ {logsQuery.isLoading && !logsQuery.data ? (
+
+
+
+ Loading logs...
+
+
+ ) : logsQuery.isError ? (
+
+
+
+
+ Error: {logsQuery.error?.message || 'Failed to load logs'}
+
+
+
+ ) : logs.length === 0 ? (
+
+ ) : (
+
+ {logs.map((log) => {
+ const formattedDate = formatDate(log.createdAt)
+ const isSelected = selectedLog?.id === log.id
+ const baseLevel = (log.level || 'info').toLowerCase()
+ const isError = baseLevel === 'error'
+ const isPending = !isError && log.hasPendingPause === true
+ const isRunning = !isError && !isPending && log.duration === null
+
+ return (
+
handleLogClick(log)}
+ >
+
+ {/* Date */}
+
+ {formattedDate.compactDate}
+
+
+ {/* Time */}
+
+ {formattedDate.compactTime}
+
+
+ {/* Status */}
+
+
+
+
+ {/* Workflow */}
+
+
+
+ {log.workflow?.name || 'Unknown'}
+
+
+
+ {/* Cost */}
+
+ {typeof log.cost?.total === 'number'
+ ? `$${log.cost.total.toFixed(4)}`
+ : '—'}
+
+
+ {/* Trigger */}
+
+ {log.trigger ? (
+
+ ) : (
+
+ —
+
+ )}
+
+
+ {/* Duration */}
+
+
+ {formatDuration(log.duration) || '—'}
+
+
+
+
+ {/* Resume Link */}
+ {isPending && log.executionId && (log.workflow?.id || log.workflowId) && (
+
e.stopPropagation()}
+ >
+
+
+ )}
+
+ )
+ })}
+
+ {/* Infinite scroll loader */}
+ {logsQuery.hasNextPage && (
+
+
+ {logsQuery.isFetchingNextPage ? (
+ <>
+
+ Loading more...
+ >
+ ) : (
+ Scroll to load more
+ )}
+
+
+ )}
+
+ )}
+
- )}
+
+ {/* Log Details - rendered inside table container */}
+
0}
+ />
+